private void RegisterAttribute(AttributeBuilderDetails variableDetails, AttributeData attribute) { switch (variableDetails.Target) { case AttributeTarget.ReturnValue: Attributes.RegisterReturnValueAttribute(variableDetails.Symbol, attribute); break; default: Attributes.RegisterAttribute(variableDetails.Symbol, attribute); break; } }
private void RegisterAttribute(AttributeBuilderDetails variableDetails, AttributeData attribute) { Log.Info($"Registering attribute '{attribute.AttributeClass}' on element '{variableDetails.Symbol}'"); switch (variableDetails.Target) { case AttributeTarget.ReturnValue: Attributes.RegisterReturnValueAttribute(variableDetails.Symbol, attribute); break; default: Attributes.RegisterAttribute(variableDetails.Symbol, attribute); break; } }
private void HandleAttributeBuilderInvocation(InvocationExpressionSyntax node, IMethodSymbol method) { // add attribute if (method.Name == "Add" && node.Expression.Kind() == SyntaxKind.SimpleMemberAccessExpression) { var memberAccess = (MemberAccessExpressionSyntax)node.Expression; AttributeBuilderDetails variableDetails = null; if (memberAccess.Expression.Kind() == SyntaxKind.InvocationExpression) { // chained method calls variableDetails = this.GetAttributesBuilderVariable(memberAccess.Expression); } else { var symbol = _semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol; if (symbol != null && symbol.Kind == SymbolKind.Local) { // variable access _variables.TryGetValue(symbol.Name, out variableDetails); } } if (variableDetails == null) { throw ReportError(Diagnostic.Create(PhaseErrors.PH012, node.Expression.GetLocation())); } foreach (var argument in node.ArgumentList.Arguments) { if (argument.Expression.Kind() != SyntaxKind.ObjectCreationExpression) { throw ReportError(Diagnostic.Create(PhaseErrors.PH013, argument.GetLocation())); } var newAttribute = (ObjectCreationExpressionSyntax)argument.Expression; var constructor = (IMethodSymbol)_semanticModel.GetSymbolInfo(newAttribute).Symbol; var constructorArguments = new List <TypedConstant>(); var namedArguments = new Dictionary <string, TypedConstant>(); for (var i = 0; i < newAttribute.ArgumentList.Arguments.Count; i++) { var ctorArgument = newAttribute.ArgumentList.Arguments[i]; var typeInfo = _semanticModel.GetTypeInfo(ctorArgument.Expression); var value = _semanticModel.GetConstantValue(ctorArgument.Expression); if (!value.HasValue) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, ctorArgument.GetLocation(), constructor.Parameters[i].Name)); } constructorArguments.Add(CreateTypedConstant(typeInfo.Type, value.Value)); } if (newAttribute.Initializer != null) { foreach (var initializerStatement in newAttribute.Initializer.Expressions) { if (initializerStatement.Kind() != SyntaxKind.SimpleAssignmentExpression) { throw ReportError(Diagnostic.Create(PhaseErrors.PH014, initializerStatement.GetLocation())); } var assignment = (AssignmentExpressionSyntax)initializerStatement; var symbol = _semanticModel.GetSymbolInfo(assignment.Left).Symbol; var typeInfo = _semanticModel.GetTypeInfo(assignment.Right); var value = _semanticModel.GetConstantValue(assignment.Right); if (!value.HasValue) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, assignment.Right.GetLocation(), symbol.Name)); } namedArguments[symbol.Name] = CreateTypedConstant(typeInfo.Type, value.Value); } } this.RegisterAttribute(variableDetails, new CustomAttributeData(constructor, constructorArguments, namedArguments));; } } else { Debug.Fail("Missing handling of method"); } }
private AttributeBuilderDetails GetAttributesBuilderVariable(ExpressionSyntax variableInitializer) { if (variableInitializer.Kind() == SyntaxKind.InvocationExpression) { InvocationExpressionSyntax invocation = (InvocationExpressionSyntax)variableInitializer; var invokedSymbol = _semanticModel.GetSymbolInfo(invocation).Symbol; if (invokedSymbol?.ContainingType == null || !invokedSymbol.ContainingType.Equals(AttributesContextType)) { return(null); } switch (invokedSymbol.Name) { case "Assembly": { IAssemblySymbol assembly; if (invocation.ArgumentList.Arguments.Count == 0) { assembly = _semanticModel.Compilation.Assembly; } else { var firstArgument = _semanticModel.GetConstantValue(invocation.ArgumentList.Arguments[0]); if (!firstArgument.HasValue) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.Arguments[0].GetLocation(), ((IMethodSymbol)invokedSymbol).Parameters[0].Name)); } var assemblyName = firstArgument.ToString(); var assemblies = _semanticModel.Compilation.References .Select(r => _semanticModel.Compilation.GetAssemblyOrModuleSymbol(r)) .Where(r => r.Kind == SymbolKind.Assembly) .ToArray(); if (_semanticModel.Compilation.Assembly.Name == assemblyName) { assembly = _semanticModel.Compilation.Assembly; } else { assembly = (IAssemblySymbol)assemblies.FirstOrDefault(r => r.Name == assemblyName); } if (assembly == null) { throw ReportError(Diagnostic.Create(PhaseErrors.PH005, invocation.ArgumentList.Arguments[0].GetLocation(), assemblyName, string.Join(", ", assemblies.Select(a => a.Name)) )); } } return(new AttributeBuilderDetails { Symbol = assembly, Target = AttributeTarget.Default }); } case "Type": { var method = (IMethodSymbol)invokedSymbol; ITypeSymbol type; if (method.TypeArguments.Length == 1) { type = method.TypeArguments[0].OriginalDefinition ?? method.TypeArguments[0]; } else { var typeofExpr = invocation.ArgumentList.Arguments[0]; if (typeofExpr.Expression.Kind() != SyntaxKind.TypeOfExpression) { throw ReportError(Diagnostic.Create(PhaseErrors.PH016, invocation.ArgumentList.Arguments[0].GetLocation() )); } type = _semanticModel.GetTypeInfo(((TypeOfExpressionSyntax)typeofExpr.Expression).Type).Type; } return(new AttributeBuilderDetails { Symbol = type, Target = AttributeTarget.Default }); } case "Member": { if (!(invocation.ArgumentList.Arguments[0].Expression is LambdaExpressionSyntax lambda) || lambda.Body == null || lambda.Body.Kind() == SyntaxKind.Block) { throw ReportError(Diagnostic.Create(PhaseErrors.PH006, invocation.ArgumentList.Arguments[0].GetLocation() )); } AttributeBuilderDetails details = new AttributeBuilderDetails(); var member = _semanticModel.GetSymbolInfo(lambda.Body).Symbol; details.Symbol = member.OriginalDefinition ?? member; string targetName = null; for (int i = 1; i < invocation.ArgumentList.Arguments.Count; i++) { var argument = invocation.ArgumentList.Arguments[i]; var type = _semanticModel.GetTypeInfo(argument.Expression).Type; var value = _semanticModel.GetConstantValue(argument.Expression); if (!value.HasValue) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.Arguments[0].GetLocation(), ((IMethodSymbol)invokedSymbol).Parameters[i].Name)); } if (type.Equals(_attributeTargetType)) { details.Target = (AttributeTarget)(int)value.Value; } else if (type.SpecialType == SpecialType.System_String) { targetName = value.Value.ToString(); } } if (targetName != null) { if (details.Target == AttributeTarget.Parameter) { if (details.Symbol.Kind == SymbolKind.Method) { details.Symbol = ((IMethodSymbol)details.Symbol).Parameters.FirstOrDefault(p => p.Name == targetName); } } } switch (details.Target) { case AttributeTarget.Default: break; case AttributeTarget.ReturnValue: if (details.Symbol.Kind != SymbolKind.Method) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.GetLocation(), details.Target, SymbolKind.Property)); } break; case AttributeTarget.Parameter: if (details.Symbol == null) { var parameterList = member.Kind == SymbolKind.Method ? ((IMethodSymbol)member).Parameters.Select(p => p.Name) : Enumerable.Empty <string>(); throw ReportError(Diagnostic.Create(PhaseErrors.PH008, invocation.ArgumentList.GetLocation(), member.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), targetName, string.Join(", ", parameterList))); } break; case AttributeTarget.Getter: { if (details.Symbol.Kind != SymbolKind.Property) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.GetLocation(), details.Target, SymbolKind.Property)); } details.Symbol = ((IPropertySymbol)details.Symbol).GetMethod; } break; case AttributeTarget.Setter: { if (details.Symbol.Kind != SymbolKind.Property) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.GetLocation(), details.Target, SymbolKind.Property)); } details.Symbol = ((IPropertySymbol)details.Symbol).SetMethod; } break; case AttributeTarget.Adder: { if (details.Symbol.Kind != SymbolKind.Event) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.GetLocation(), details.Target, SymbolKind.Event)); } details.Symbol = ((IEventSymbol)details.Symbol).AddMethod; } break; case AttributeTarget.Remover: { if (details.Symbol.Kind != SymbolKind.Event) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.GetLocation(), details.Target, SymbolKind.Event)); } details.Symbol = ((IEventSymbol)details.Symbol).RemoveMethod; } break; } return(details); } case "Constructor": { if (!(invocation.ArgumentList.Arguments[0].Expression is LambdaExpressionSyntax lambda) || lambda.Body == null || lambda.Body.Kind() == SyntaxKind.Block) { throw ReportError(Diagnostic.Create(PhaseErrors.PH006, invocation.ArgumentList.Arguments[0].GetLocation() )); } var member = _semanticModel.GetSymbolInfo(lambda.Body).Symbol; if (member.Kind != SymbolKind.Method || ((IMethodSymbol)member).MethodKind != MethodKind.Constructor) { throw ReportError(Diagnostic.Create(PhaseErrors.PH009, invocation.ArgumentList.Arguments[0].GetLocation())); } AttributeBuilderDetails details = new AttributeBuilderDetails(); details.Symbol = member.OriginalDefinition ?? member; return(details); } case "Event": { var eventName = _semanticModel.GetConstantValue(invocation.ArgumentList.Arguments[0].Expression); if (!eventName.HasValue) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.Arguments[0].GetLocation(), ((IMethodSymbol)invokedSymbol).Parameters[0].Name)); } var type = ((IMethodSymbol)invokedSymbol).TypeArguments[0]; var events = type.GetMembers() .Where(m => m.Kind == SymbolKind.Event); var eventSymbol = events.FirstOrDefault(e => e.Name == eventName.Value.ToString()); if (!eventName.HasValue) { throw ReportError(Diagnostic.Create(PhaseErrors.PH010, invocation.ArgumentList.Arguments[0].GetLocation(), eventName.Value, type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), string.Join(", ", events.Select(e => e.Name)))); } AttributeBuilderDetails details = new AttributeBuilderDetails(); details.Symbol = eventSymbol.OriginalDefinition ?? eventSymbol; for (int i = 1; i < invocation.ArgumentList.Arguments.Count; i++) { var argument = invocation.ArgumentList.Arguments[i]; var argumentType = _semanticModel.GetTypeInfo(argument).Type; var value = _semanticModel.GetConstantValue(argument.Expression); if (!value.HasValue) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.Arguments[0].GetLocation(), ((IMethodSymbol)invokedSymbol).Parameters[i].Name)); } if (argumentType.Equals(_attributeTargetType)) { details.Target = (AttributeTarget)(int)value.Value; } } switch (details.Target) { case AttributeTarget.Default: break; case AttributeTarget.Adder: { if (details.Symbol.Kind != SymbolKind.Event) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.GetLocation(), details.Target, SymbolKind.Event)); } details.Symbol = ((IEventSymbol)details.Symbol).AddMethod; } break; case AttributeTarget.Remover: { if (details.Symbol.Kind != SymbolKind.Event) { throw ReportError(Diagnostic.Create(PhaseErrors.PH004, invocation.ArgumentList.GetLocation(), details.Target, SymbolKind.Event)); } details.Symbol = ((IEventSymbol)details.Symbol).RemoveMethod; } break; } return(details); } } } return(null); }