Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » C# » General » Downloads
 
Add your own
alternative version
Go to top

Roslyn CTP: Three Introductory Projects

, 8 May 2012
An introduction to the Roslyn CTP
RoslynCTPSamples.zip
CodeGenerator
bin
Debug
CodeGenerator.vshost.exe
CodeGenerator.vshost.exe.manifest
Release
CodeGenerator.csproj.user
obj
x86
Debug
DesignTimeResolveAssemblyReferences.cache
DesignTimeResolveAssemblyReferencesInput.cache
TempPE
Properties
EventImplementer
bin
Debug
Release
EventImplementer.csproj.user
obj
Debug
DesignTimeResolveAssemblyReferencesInput.cache
TempPE
Properties
source.extension.vsixmanifest
RoslynCTPSamples.suo
RoslynCTPSamples.vsmdi
RoslynCTPLibrary
bin
Debug
RoslynCTPSamples.dll
RoslynCTPSamples.pdb
Release
obj
Debug
DesignTimeResolveAssemblyReferencesInput.cache
RoslynCTPSamples.dll
RoslynCTPSamples.pdb
TempPE
Properties
CodeGeneratorTest
bin
Debug
obj
Debug
DesignTimeResolveAssemblyReferencesInput.cache
TempPE
Properties
RefactoringConsole
bin
Debug
RefactoringConsole.vshost.exe
RefactoringConsole.vshost.exe.manifest
obj
x86
Debug
DesignTimeResolveAssemblyReferencesInput.cache
TempPE
Properties
RefactoringExtension
bin
Debug
Release
obj
Debug
DesignTimeResolveAssemblyReferencesInput.cache
TempPE
Properties
RefactoringExtension.csproj.user
source.extension.vsixmanifest
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using Roslyn.Compilers;
using Roslyn.Compilers.Common;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;
using Roslyn.Services.Editor;
using RoslynCTPLibrary.Attributes;
using RoslynCTPLibrary.Extensions;
using System.Reactive.Subjects;

namespace EventImplementer {
    [ExportSyntaxNodeCodeIssueProvider("EventImplementer", LanguageNames.CSharp, typeof(PropertyDeclarationSyntax))]
    class CodeIssueProvider : ICodeIssueProvider {
        private readonly ICodeActionEditFactory editFactory;

        [ImportingConstructor]
        public CodeIssueProvider(ICodeActionEditFactory editFactory) {
            this.editFactory = editFactory;
        }

        public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken) {
            var property = node as PropertyDeclarationSyntax;

            if (!property.Attributes.Any(ad => ad.Attributes.Any(a => a.Name.PlainName == typeof(FiresEventOnChange).Name || a.Name.PlainName == typeof(FiresEventOnQuery).Name))
                || property.GetOwnerType().Members.OfType<FieldDeclarationSyntax>().Any(f => f.Declaration.Variables.First().Identifier.ValueText == Constants.FieldPrefix + property.Identifier.ValueText))
                yield break;

            yield return new CodeIssue(CodeIssue.Severity.Error, property.Span, "Event needs to be implemented", new CodeAction(editFactory, document, property));
        }


        public class CodeAction : ICodeAction {
            public string Description { get { return "Implement event"; } }
            public System.Windows.Media.ImageSource Icon { get { return null; } }

            ICodeActionEditFactory EditFactory;
            IDocument Document;
            PropertyDeclarationSyntax Property;

            public CodeAction(ICodeActionEditFactory editFactory, IDocument document, PropertyDeclarationSyntax property) {
                EditFactory = editFactory; Document = document; Property = property;
            }

            public ICodeActionEdit GetEdit(CancellationToken cancellationToken) {
                var backingField = Syntax.FieldDeclaration(declaration: Syntax.VariableDeclaration(Property.Type, Syntax.SeparatedList(Syntax.VariableDeclarator(identifier: Syntax.Identifier(Constants.FieldPrefix + Property.Identifier.ValueText)))));

                var getStatements = new List<StatementSyntax> { Syntax.ReturnStatement(returnKeyword: Syntax.Token(SyntaxKind.ReturnKeyword), expressionOpt: Syntax.IdentifierName(backingField.Declaration.Variables.First().Identifier)) };
                var setStatements = new List<StatementSyntax> { Syntax.ExpressionStatement(Syntax.BinaryExpression(SyntaxKind.AssignExpression, Syntax.IdentifierName(backingField.Declaration.Variables.First().Identifier.ValueText), 
                                                                                                                    right: Syntax.IdentifierName(Syntax.Token(SyntaxKind.ValueKeyword)))) };
                var newMembers = new List<MemberDeclarationSyntax> { backingField };


                Func<string, FieldDeclarationSyntax> subjectDeclaration = suffix =>
                    Syntax.FieldDeclaration(modifiers: Syntax.TokenList(Syntax.Token(SyntaxKind.PublicKeyword)),
                        declaration: Syntax.VariableDeclaration(Syntax.GenericName(Syntax.ParseToken(typeof(Subject).Name), Syntax.TypeArgumentList(arguments: Syntax.SeparatedList<TypeSyntax>(Property.Type))),
                            variables: Syntax.SeparatedList(Syntax.VariableDeclarator(Syntax.Identifier(Property.Identifier.ValueText + suffix),
                                initializerOpt: Syntax.EqualsValueClause(value: Syntax.ObjectCreationExpression(
                                    type: Syntax.GenericName(Syntax.ParseToken(typeof(Subject).Name), Syntax.TypeArgumentList(arguments: Syntax.SeparatedList<TypeSyntax>(Property.Type))),
                                    argumentListOpt: Syntax.ArgumentList()))))));

                Func<string, ExpressionSyntax, ExpressionStatementSyntax> onNextCall = (suffix, argumentExpression) =>
                    Syntax.ExpressionStatement(Syntax.InvocationExpression(Syntax.MemberAccessExpression(SyntaxKind.MemberAccessExpression, Syntax.IdentifierName(Property.Identifier.ValueText + suffix),
                        name: Syntax.IdentifierName("OnNext")), Syntax.ArgumentList(arguments: Syntax.SeparatedList(Syntax.Argument(expression: argumentExpression)))));


                if (Property.Attributes.Any(ad => ad.Attributes.Any(a => a.Name.PlainName == typeof(FiresEventOnQuery).Name))) {
                    newMembers.Add(subjectDeclaration(Constants.QueriedSuffix));
                    getStatements.Insert(0, onNextCall(Constants.QueriedSuffix, Syntax.IdentifierName(backingField.Declaration.Variables.First().Identifier.ValueText)));
                }

                if (Property.Attributes.Any(ad => ad.Attributes.Any(a => a.Name.PlainName == typeof(FiresEventOnChange).Name))) {
                    newMembers.Add(subjectDeclaration(Constants.ChangedSuffix));
                    setStatements.Add(onNextCall(Constants.ChangedSuffix, Syntax.IdentifierName(Syntax.Token(SyntaxKind.ValueKeyword))));
                }


                newMembers.Add(Property.Update(Property.Attributes, Property.Modifiers, Property.Type, Property.ExplicitInterfaceSpecifierOpt, Property.Identifier,
                    Syntax.AccessorList(accessors: Syntax.List<AccessorDeclarationSyntax>(
                        Syntax.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration, bodyOpt: Syntax.Block(statements: Syntax.List<StatementSyntax>(getStatements))),
                        Syntax.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration, bodyOpt: Syntax.Block(statements: Syntax.List<StatementSyntax>(setStatements)))
                    ))));

                var typeDecl = Property.GetOwnerType();

                var propertyIndex = typeDecl.Members.IndexOf(Property);
                var newtypeDecl = Syntax.TypeDeclaration(typeDecl.Kind, typeDecl.Attributes, typeDecl.Modifiers, typeDecl.Keyword, typeDecl.Identifier, typeDecl.TypeParameterListOpt, typeDecl.BaseListOpt, typeDecl.ConstraintClauses, typeDecl.OpenBraceToken,
                    Syntax.List(typeDecl.Members.Take(propertyIndex).Concat(newMembers.AsEnumerable().Reverse()).Concat(typeDecl.Members.Skip(propertyIndex + 1))), typeDecl.CloseBraceToken, typeDecl.SemicolonTokenOpt).Format();

                return EditFactory.CreateTreeTransformEdit(Document.Project.Solution, Document.GetSyntaxTree(), ((SyntaxNode)Document.GetSyntaxTree().Root).ReplaceNode(typeDecl, newtypeDecl));
            }
        }

        #region Unimplemented ICodeIssueProvider members

        public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxToken token, CancellationToken cancellationToken) {
            throw new NotImplementedException();
        }

        public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxTrivia trivia, CancellationToken cancellationToken) {
            throw new NotImplementedException();
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Whaeth

Hungary Hungary
No Biography provided

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 8 May 2012
Article Copyright 2011 by Whaeth
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid