private void HandleDeclaration(SyntaxNodeAnalysisContext context, TypeSyntax returnType) { var predefinedType = returnType as PredefinedTypeSyntax; if (predefinedType != null && predefinedType.Keyword.IsKind(SyntaxKind.VoidKeyword)) { // There is no return value return; } var documentationStructure = context.Node.GetDocumentationCommentTriviaSyntax(); if (documentationStructure == null) { return; } if (documentationStructure.Content.GetFirstXmlElement(XmlCommentHelper.InheritdocXmlTag) != null) { // Don't report if the documentation is inherited. return; } if (documentationStructure.Content.GetFirstXmlElement(XmlCommentHelper.ReturnsXmlTag) == null) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, returnType.GetLocation())); } }
private static void ReportIfListT(TypeSyntax typeSyntax, SyntaxNodeAnalysisContext context, string memberType) { if (typeSyntax != null && typeSyntax.IsKnownType(KnownType.System_Collections_Generic_List_T, context.SemanticModel)) { context.ReportDiagnosticWhenActive(Diagnostic.Create(Rule, typeSyntax.GetLocation(), messageArgs: memberType)); } }
internal static bool IsCommand(this TypeSyntax value, SemanticModel semanticModel) { var name = value.ToString(); return(name.Contains("Command") && semanticModel.LookupSymbols(value.GetLocation().SourceSpan.Start, name: name).FirstOrDefault() is ITypeSymbol symbol && symbol.IsCommand()); }
private static void HandleDeclaration(SyntaxNodeAnalysisContext context, bool needsComment, TypeSyntax returnType) { if (!needsComment) { // Documentation is optional for this element. return; } var predefinedType = returnType as PredefinedTypeSyntax; if (predefinedType != null && predefinedType.Keyword.IsKind(SyntaxKind.VoidKeyword)) { // There is no return value return; } var documentationStructure = context.Node.GetDocumentationCommentTriviaSyntax(); if (documentationStructure == null) { return; } if (documentationStructure.Content.GetFirstXmlElement(XmlCommentHelper.InheritdocXmlTag) != null) { // Don't report if the documentation is inherited. return; } var relevantXmlElement = documentationStructure.Content.GetFirstXmlElement(XmlCommentHelper.ReturnsXmlTag); if (relevantXmlElement != null) { // A <returns> element was located. return; } relevantXmlElement = documentationStructure.Content.GetFirstXmlElement(XmlCommentHelper.IncludeXmlTag); if (relevantXmlElement != null) { var declaration = context.SemanticModel.GetDeclaredSymbol(context.Node, context.CancellationToken); var rawDocumentation = declaration?.GetDocumentationCommentXml(expandIncludes: true, cancellationToken: context.CancellationToken); XElement completeDocumentation = XElement.Parse(rawDocumentation, LoadOptions.None); if (completeDocumentation.Nodes().OfType <XElement>().Any(element => element.Name == XmlCommentHelper.InheritdocXmlTag)) { // Ignore nodes with an <inheritdoc/> tag in the included XML. return; } if (completeDocumentation.Nodes().OfType <XElement>().Any(element => element.Name == XmlCommentHelper.ReturnsXmlTag)) { // A <returns> element was located. return; } } context.ReportDiagnostic(Diagnostic.Create(Descriptor, returnType.GetLocation())); }
protected override TypeWithNode HandleTypeName(TypeSyntax node, IEnumerable <TypeSyntax>?typeArguments) { TypeWithNode[] typeArgs = typeArguments?.Select(s => s.Accept(this)).ToArray() ?? new TypeWithNode[0]; var symbolInfo = semanticModel.GetSymbolInfo(node, cancellationToken); switch (symbolInfo.Symbol) { case INamedTypeSymbol ty: var alias = semanticModel.GetAliasInfo(node, cancellationToken); if (alias != null) { typeArgs = typeSystem.GetSymbolType(alias).TypeArguments.ToArray(); } else { typeArgs = InheritOuterTypeArguments(typeArgs, ty); Debug.Assert(ty.FullArity() == typeArgs.Length); foreach (var(tp, ta) in ty.FullTypeParameters().Zip(typeArgs)) { if (tp.HasNotNullConstraint) { var edge = typeSystemBuilder.CreateEdge(ta.Node, typeSystem.NonNullNode); edge?.SetLabel("nonnull constraint", node.GetLocation()); } } } if (ty.CanBeMadeNullable() && CanBeMadeNullableSyntax(node)) { return(new TypeWithNode(ty, mapping[node], typeArgs)); } else { return(new TypeWithNode(ty, typeSystem.ObliviousNode, typeArgs)); } case ITypeParameterSymbol tp: if (tp.HasReferenceTypeConstraint && CanBeMadeNullableSyntax(node)) { return(new TypeWithNode(tp, mapping[node], typeArgs)); } else { return(new TypeWithNode(tp, typeSystem.ObliviousNode, typeArgs)); } case IPointerTypeSymbol pts: return(new TypeWithNode(pts, typeSystem.ObliviousNode, typeArgs)); case IArrayTypeSymbol ats: return(new TypeWithNode(ats, mapping[node], typeArgs)); default: return(typeSystem.VoidType); } }
/// <summary> /// Generates the warning information indicating mismatch in the parameter types of the command methods. /// </summary> /// <param name="method1">The declaration of the first method.</param> /// <param name="method2">The declaration of the second method.</param> /// <param name="type">The syntax of the mismatched type of the parameter.</param> /// <param name="command">The identifier of the command.</param> private void WarningParameter(MethodDeclarationSyntax method1, MethodDeclarationSyntax method2, TypeSyntax type, string command) { FileLinePositionSpan span = type.GetLocation().GetLineSpan(); if (span.IsValid) { GenerateWarning(string.Format(Strings.ParameterTypeMismatch, method1.Identifier.ValueText, method2.Identifier.ValueText, command), span.StartLinePosition.Line + 1, span.StartLinePosition.Character + 1); return; } GenerateWarning(string.Format(Strings.ParameterTypeMismatch, method1.Identifier.ValueText, method2.Identifier.ValueText, command)); }
void Populate() { switch (Syntax.Kind()) { case SyntaxKind.ArrayType: var ats = (ArrayTypeSyntax)Syntax; var at = (ArrayType)Type; Emit(Loc ?? Syntax.GetLocation(), Parent, Type); Create(cx, ats.ElementType, this, at.ElementType); return; case SyntaxKind.NullableType: var nts = (NullableTypeSyntax)Syntax; var nt = (NamedType)Type; Emit(Loc ?? Syntax.GetLocation(), Parent, Type); Create(cx, nts.ElementType, this, nt.TypeArguments[0]); return; case SyntaxKind.TupleType: var tts = (TupleTypeSyntax)Syntax; var tt = (TupleType)Type; Emit(Loc ?? Syntax.GetLocation(), Parent, Type); tts.Elements.Zip(tt.TupleElements, (s, t) => Create(cx, s.Type, this, t.Type)).Enumerate(); return; case SyntaxKind.PointerType: var pts = (PointerTypeSyntax)Syntax; var pt = (PointerType)Type; Emit(Loc ?? Syntax.GetLocation(), Parent, Type); Create(cx, pts.ElementType, this, pt.PointedAtType); return; case SyntaxKind.GenericName: var gns = (GenericNameSyntax)Syntax; Emit(Loc ?? gns.Identifier.GetLocation(), Parent, Type); cx.PopulateLater(() => gns.TypeArgumentList.Arguments.Zip(Type.TypeMentions, (s, t) => Create(cx, s, this, t)).Enumerate()); return; case SyntaxKind.QualifiedName: if (Type.ContainingType == null) { // namespace qualifier Emit(Loc ?? Syntax.GetLocation(), Parent, Type); } else { // Type qualifier var qns = (QualifiedNameSyntax)Syntax; var right = Create(cx, qns.Right, Parent, Type); Create(cx, qns.Left, right, Type.ContainingType); } return; default: Emit(Loc ?? Syntax.GetLocation(), Parent, Type); return; } }
private void AnalyzeEventType(SyntaxNodeAnalysisContext analysisContext, TypeSyntax typeSyntax) { var eventHandlerType = analysisContext.SemanticModel.GetSymbolInfo(typeSyntax).Symbol as INamedTypeSymbol; if (eventHandlerType == null) { return; } if (!eventHandlerType.ConstructedFrom.Is(KnownType.System_EventHandler_TEventArgs)) { analysisContext.ReportDiagnostic(Diagnostic.Create(rule, typeSyntax.GetLocation())); } }
private void AnalyzeEventType(SyntaxNodeAnalysisContext analysisContext, TypeSyntax typeSyntax) { var eventHandlerType = analysisContext.SemanticModel.GetSymbolInfo(typeSyntax).Symbol as INamedTypeSymbol; var methodSymbol = eventHandlerType?.DelegateInvokeMethod; if (methodSymbol == null) { return; } if (!IsCorrectEventHandlerSignature(methodSymbol)) { analysisContext.ReportDiagnosticWhenActive(Diagnostic.Create(rule, typeSyntax.GetLocation())); } }
protected override Location GetCorrespondingBaseListLocation(NamedTypeSymbol @base) { Location backupLocation = null; var unusedDiagnostics = DiagnosticBag.GetInstance(); foreach (SyntaxReference part in SyntaxReferences) { TypeDeclarationSyntax typeBlock = (TypeDeclarationSyntax)part.GetSyntax(); BaseListSyntax bases = typeBlock.BaseList; if (bases == null) { continue; } SeparatedSyntaxList <BaseTypeSyntax> inheritedTypeDecls = bases.Types; var baseBinder = this.DeclaringCompilation.GetBinder(bases); baseBinder = baseBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this); if ((object)backupLocation == null) { backupLocation = inheritedTypeDecls[0].Type.GetLocation(); } foreach (BaseTypeSyntax baseTypeSyntax in inheritedTypeDecls) { TypeSyntax t = baseTypeSyntax.Type; TypeSymbol bt = baseBinder.BindType(t, unusedDiagnostics); if (bt == @base) { unusedDiagnostics.Free(); return(t.GetLocation()); } } } unusedDiagnostics.Free(); return(backupLocation); }
protected override void Populate(TextWriter trapFile) { switch (syntax.Kind()) { case SyntaxKind.ArrayType: case SyntaxKind.PointerType: Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); Create(Context, GetArrayElementType(syntax), this, GetArrayElementType(type)); return; case SyntaxKind.NullableType: var nts = (NullableTypeSyntax)syntax; if (type is NamedType nt) { if (!nt.Symbol.IsReferenceType) { Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); Create(Context, nts.ElementType, this, nt.TypeArguments[0]); } else { Create(Context, nts.ElementType, parent, type); } } else if (type is ArrayType) { Create(Context, nts.ElementType, parent, type); } return; case SyntaxKind.TupleType: var tts = (TupleTypeSyntax)syntax; var tt = (TupleType)type; Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); foreach (var(s, t) in tts.Elements.Zip(tt.TupleElements, (s, t) => (s, t?.Type))) { if (t is not null) { Create(Context, s.Type, this, t); } } return; case SyntaxKind.GenericName: Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); Context.PopulateLater(() => ((GenericNameSyntax)syntax) .TypeArgumentList .Arguments .Zip(type.TypeMentions, (s, t) => Create(Context, s, this, t)).Enumerate()); return; case SyntaxKind.QualifiedName: var qns = (QualifiedNameSyntax)syntax; var right = Create(Context, qns.Right, parent, type); if (type.ContainingType is not null) { // Type qualifier Create(Context, qns.Left, right, type.ContainingType); } return; default: Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); return; } }
private static SchemaTypeInfo GetSchemaTypeInfo(TypeSyntax typeSyntax) { var info = new SchemaTypeInfo(); switch (typeSyntax) { case PredefinedTypeSyntax predefinedType: info.TypeName = predefinedType.Keyword.ValueText; info.Syntax = SchemaTypeInfo.SyntaxType.primitive; break; case IdentifierNameSyntax identifierName: info.Syntax = SchemaTypeInfo.SyntaxType.complex; info.TypeName = identifierName.Identifier.Text; break; case NullableTypeSyntax nullableType: info.Syntax = SchemaTypeInfo.SyntaxType.nullable; var np = nullableType.ElementType as PredefinedTypeSyntax; info.TypeName = np.Keyword.ValueText; break; case GenericNameSyntax genericType: info.TypeName = genericType.Identifier.Text; info.Syntax = SchemaTypeInfo.SyntaxType.generic; info.GenericParameters = new List <SchemaTypeInfo>(); foreach (var a in genericType.TypeArgumentList.Arguments) { info.GenericParameters.Add(GetSchemaTypeInfo(a)); } break; case ArrayTypeSyntax arrayType: info = GetSchemaTypeInfo(arrayType.ElementType); info.Syntax = SchemaTypeInfo.SyntaxType.array; break; default: throw new Exception($"Unknown TypeSyntax {typeSyntax.GetType()} at line {typeSyntax.GetLocation().GetLineSpan().StartLinePosition.Line}"); } return(info); }
public void Execute(GeneratorExecutionContext context) { if (!(context.SyntaxReceiver is DuckSyntaxInvocationReceiver receiver)) { return; } var duckableAttribute = context.Compilation.GetTypeByMetadataName("DuckableAttribute"); if (context.CancellationToken.IsCancellationRequested) { return; } var ducksFromInvocations = GetDucksFromInvocations(); var ducksFromVariableDeclarations = GetDucksFromVariableDeclarations(); var ducks = ducksFromInvocations .Concat(ducksFromVariableDeclarations) .Distinct() .ToArray(); if (context.CancellationToken.IsCancellationRequested) { return; } foreach (var(duckInterface, typeToDuck) in ducks) { var uniqueName = $"{duckInterface.ToGlobalName().Replace("global::", "")}_{typeToDuck.ToGlobalName().Replace("global::", "")}"; var properties = duckInterface .GetMembers() .OfType <IPropertySymbol>() .SelectMany(o => { var getter = o.GetMethod != null ? $" _{o.Name}Getter = () => value.{o.Name};" : string.Empty; var setter = o.SetMethod != null ? $" _{o.Name}Setter = o => value.{o.Name} = o;" : string.Empty; return(new[] { getter, setter }); }) .Where(o => !string.IsNullOrEmpty(o)) .JoinWithNewLine(); var methods = duckInterface .GetAllMembers() .GetPublicMethods() .Select(o => $" _{o.Name} = value.{o.Name};") .JoinWithNewLine(); var source = $@" using System; namespace {(duckInterface.ContainingNamespace.ToDisplayString())} {{ public partial class D{duckInterface.Name} {{ private D{duckInterface.Name}({typeToDuck.ToGlobalName()} value) {{ {properties} {methods} }} public static implicit operator D{duckInterface.Name}({typeToDuck.ToGlobalName()} value) {{ return new D{duckInterface.Name}(value); }} }} }} "; if (context.CancellationToken.IsCancellationRequested) { return; } context.AddSource(uniqueName, source.ToSourceText()); } IEnumerable <(ITypeSymbol DuckInteface, ITypeSymbol TypeToDuck)> GetDucksFromInvocations() { foreach (var invocation in receiver.Invocations) { if (context.CancellationToken.IsCancellationRequested) { yield break; } var semanticModel = context.Compilation.GetSemanticModel(invocation.SyntaxTree); var symbol = semanticModel.GetSpeculativeSymbolInfo(invocation.SpanStart, invocation, SpeculativeBindingOption.BindAsExpression); var call = symbol.CandidateSymbols.FirstOrDefault() as IMethodSymbol; if (call is null) { continue; } for (int i = 0; i < call.Parameters.Length; i++) { var parameter = call.Parameters[i]; if (!parameter.Type.Name.StartsWith("DI")) { continue; } var nameWithoutD = parameter.Type.Name.Substring(1); var duckInterface = context.Compilation .GetSymbolsWithName(o => o.EndsWith(nameWithoutD), SymbolFilter.Type, context.CancellationToken) .OfType <ITypeSymbol>() .FirstOrDefault(s => s .GetAttributes() .Any(attr => attr.AttributeClass.Equals(duckableAttribute))); if (duckInterface is null) { continue; } TypeSyntax argumentSyntax = null; switch (invocation.ArgumentList.Arguments[i].Expression) { case IdentifierNameSyntax name: argumentSyntax = name; break; case ObjectCreationExpressionSyntax ctor: argumentSyntax = ctor.Type; break; } if (argumentSyntax is null) { continue; } var speculativeArgumentSymbol = semanticModel .GetSpeculativeSymbolInfo(argumentSyntax.SpanStart, argumentSyntax, SpeculativeBindingOption.BindAsExpression); var duckableSymbol = speculativeArgumentSymbol.GetTypeSymbol(); var isDuckable = duckInterface.IsTypeDuckableTo(duckableSymbol); if (isDuckable.IsDuckable) { yield return(duckInterface, duckableSymbol); } else { context.ReportDiagnostic(Diagnostic.Create(DuckMappingCantBeDone, argumentSyntax.GetLocation(), duckInterface.Name, duckableSymbol.Name, isDuckable.MissingSymbols.Select(o => o.Name).JoinWithNewLine())); } } } } IEnumerable <(ITypeSymbol DuckInteface, ITypeSymbol TypeToDuck)> GetDucksFromVariableDeclarations() { foreach (var variableDeclaration in receiver.VariableDeclarations) { if (context.CancellationToken.IsCancellationRequested) { yield break; } var semanticModel = context.Compilation.GetSemanticModel(variableDeclaration.SyntaxTree); var nameWithoutD = variableDeclaration.Type.ToString().Substring(1); var duckInterface = context.Compilation .GetSymbolsWithName(o => o.EndsWith(nameWithoutD), SymbolFilter.Type, context.CancellationToken) .OfType <ITypeSymbol>() .FirstOrDefault(s => s .GetAttributes() .Any(attr => attr.AttributeClass.Equals(duckableAttribute))); if (duckInterface is null) { continue; } var value = variableDeclaration.DescendantNodes().OfType <EqualsValueClauseSyntax>().First().Value; var typeToDuckSymbol = semanticModel.GetSpeculativeSymbolInfo(value.SpanStart, value, SpeculativeBindingOption.BindAsExpression); var typeToDuck = typeToDuckSymbol.GetTypeSymbol(); if (typeToDuck is null) { continue; } yield return(duckInterface, typeToDuck); } } }
protected override void Populate(TextWriter trapFile) { switch (Syntax.Kind()) { case SyntaxKind.ArrayType: Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); Create(cx, GetElementType(Syntax), this, GetElementType(Type)); return; case SyntaxKind.NullableType: var nts = (NullableTypeSyntax)Syntax; if (Type is NamedType nt) { Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); Create(cx, nts.ElementType, this, nt.symbol.IsReferenceType ? nt : nt.TypeArguments[0]); } else if (Type is ArrayType array) { Create(cx, nts.ElementType, Parent, array); } return; case SyntaxKind.TupleType: var tts = (TupleTypeSyntax)Syntax; var tt = (TupleType)Type; Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); tts.Elements.Zip(tt.TupleElements, (s, t) => Create(cx, s.Type, this, t.Type)).Enumerate(); return; case SyntaxKind.PointerType: var pts = (PointerTypeSyntax)Syntax; var pt = (PointerType)Type; Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); Create(cx, pts.ElementType, this, pt.PointedAtType); return; case SyntaxKind.GenericName: var gns = (GenericNameSyntax)Syntax; Emit(trapFile, Loc ?? gns.Identifier.GetLocation(), Parent, Type); cx.PopulateLater(() => gns.TypeArgumentList.Arguments.Zip(Type.TypeMentions, (s, t) => Create(cx, s, this, t)).Enumerate()); return; case SyntaxKind.QualifiedName: if (Type.ContainingType == null) { // namespace qualifier Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); } else { // Type qualifier var qns = (QualifiedNameSyntax)Syntax; var right = Create(cx, qns.Right, Parent, Type); Create(cx, qns.Left, right, Type.ContainingType); } return; default: Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type); return; } }
public static string GetFullTypeName(this SemanticModel model, TypeSyntax type, out bool isArray) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (type == null) { throw new ArgumentNullException(nameof(type)); } if (type.SyntaxTree != model.SyntaxTree) { model = GetSemanticModel(model.Compilation, type.SyntaxTree); } TypeInfo typeInfo = model.GetTypeInfo(type); if (typeInfo.Type == null) { typeInfo = model.GetSpeculativeTypeInfo(0, type, SpeculativeBindingOption.BindAsTypeOrNamespace); if (typeInfo.Type == null || typeInfo.Type is IErrorTypeSymbol) { throw new InvalidOperationException("Unable to resolve type: " + type + " at " + type.GetLocation()); } } return(GetFullTypeName(typeInfo.Type, out isArray)); }
private static void CheckType(SyntaxNodeAnalysisContext context, TypeSyntax typeSyntax, Location reportLocation = null) { switch (typeSyntax.Kind()) { case SyntaxKindEx.TupleType: CheckTupleType(context, (TupleTypeSyntaxWrapper)typeSyntax, reportLocation); break; case SyntaxKind.QualifiedName: CheckType(context, ((QualifiedNameSyntax)typeSyntax).Right, reportLocation ?? typeSyntax.GetLocation()); break; case SyntaxKind.GenericName: CheckGenericName(context, (GenericNameSyntax)typeSyntax, reportLocation); break; } }
private void AnalyzeNode(SyntaxNodeAnalysisContext context) { var node = (ObjectCreationExpressionSyntax)context.Node; var engineType = node.Type.ToString().TrimPhraseStart("FileHelpers."); if (engineType.StartsWithAnyIgnoreCase("FileHelperEngine", "FileHelperAsyncEngine")) { TypeSyntax recordSyntax = null; if (node.ArgumentList.Arguments.Count > 0 && node.ArgumentList.Arguments[0].Expression is TypeOfExpressionSyntax) { var typeofSyntax = (TypeOfExpressionSyntax)node.ArgumentList.Arguments[0].Expression; recordSyntax = typeofSyntax.Type; } if (recordSyntax == null) { var type = node.Type as GenericNameSyntax; if (type != null) { recordSyntax = type.TypeArgumentList.Arguments[0]; } } if (recordSyntax != null) { var recordType = context.SemanticModel.GetTypeInfo(recordSyntax); if (recordType.Type.BaseType.Name == "Object") { var attributes = recordType.Type.GetAttributes(); if ( attributes.Count( x => x.AttributeClass.Name == "DelimitedRecordAttribute" || x.AttributeClass.Name == "FixedLengthRecordAttribute") == 0) { var diagnostic = Diagnostic.Create(Rule, recordType.Type.OriginalDefinition.Locations.FirstOrDefault(), (IEnumerable <Location>) new [] { recordSyntax.GetLocation() }); context.ReportDiagnostic(diagnostic); } } } } }