/// <summary> /// Normalizes the given <paramref name="methodDeclaration" /> and adds the generated members. The method ensures that the /// normalized method is marked with <paramref name="attribute" />, if non-<c>null</c>. /// </summary> /// <param name="methodDeclaration">The method declaration that should be normalized.</param> /// <param name="attribute">The attribute the generated method should be marked with.</param> private MethodDeclarationSyntax NormalizeMethod(MethodDeclarationSyntax methodDeclaration, Type attribute = null) { var originalDeclaration = methodDeclaration; var methodDelegate = CreateDelegate(methodDeclaration); var methodField = CreateField(methodDelegate); // Create the private port implementation method var methodName = ("Behavior" + _portCount).ToSynthesized(); var portImplementationName = SyntaxFactory.Identifier(methodName).WithTrivia(originalDeclaration.Identifier); var portImplementation = originalDeclaration.WithIdentifier(portImplementationName); portImplementation = portImplementation.WithAccessibility(Accessibility.Private).WithExplicitInterfaceSpecifier(null); // Remove all modifiers from the port implementation except for the 'private' keyword var modifiers = portImplementation.Modifiers; var privateKeyword = modifiers[modifiers.IndexOf(SyntaxKind.PrivateKeyword)]; portImplementation = portImplementation.WithModifiers(SyntaxTokenList.Create(privateKeyword)); // Replace all original attributes with their global name, as the required 'usings' are not present in the generated file var attributeSymbols = originalDeclaration.GetMethodSymbol(SemanticModel).GetAttributes(); if (attributeSymbols.Length != 0) { var attributes = attributeSymbols.Select(a => (AttributeListSyntax)Syntax.Attribute(a)); methodDeclaration = methodDeclaration.WithAttributeLists(SyntaxFactory.List(attributes)); } // Add the requested attribute if it is not already present if (attribute != null && !originalDeclaration.HasAttribute(SemanticModel, attribute)) { var attributeSyntax = (AttributeListSyntax)Syntax.Attribute(attribute.FullName).WithTrailingSpace(); methodDeclaration = methodDeclaration.WithAttributeLists(methodDeclaration.AttributeLists.Add(attributeSyntax)); } // Replace the method's body and ensure that we don't modify the line count of the containing type // We don't change abstract methods, however, except for adding the requested attribute, if necessary if (methodDeclaration.Modifiers.IndexOf(SyntaxKind.AbstractKeyword) != -1) return methodDeclaration; // Add the [MethodBehavior] attribute var behaviorArgument = SyntaxFactory.ParseExpression(String.Format("\"{0}\"", methodName)); var behaviorAttribute = SyntaxBuilder.Attribute(typeof(IntendedBehaviorAttribute).FullName, behaviorArgument); methodDeclaration = methodDeclaration.WithAttributeLists(methodDeclaration.AttributeLists.Add(behaviorAttribute)); // Add the [DebuggerHidden] attribute if not already present if (!originalDeclaration.HasAttribute<DebuggerHiddenAttribute>(SemanticModel)) methodDeclaration = methodDeclaration.WithAttributeLists(methodDeclaration.AttributeLists.Add(_debuggerHiddenAttribute)); // Add the [Ignore] attribute if not already present if (!originalDeclaration.HasAttribute<SuppressTransformationAttribute>(SemanticModel)) { portImplementation = portImplementation.WithAttributeLists(portImplementation.AttributeLists.Add(_ignoreAttribute)); portImplementation = portImplementation.RemoveComments().WithTrivia(originalDeclaration); } // Add the backing field attribute and replace the method body methodDeclaration = AddBackingFieldAttribute(methodDeclaration); methodDeclaration = ReplaceBodyWithDelegateInvocation(methodDeclaration); methodDeclaration = methodDeclaration.RemoveComments().WithTrivia(originalDeclaration); ++_portCount; AddMembers(originalDeclaration.GetMethodSymbol(SemanticModel).ContainingType, methodField, methodDelegate, methodDeclaration); return portImplementation.EnsureLineCount(originalDeclaration); }