/// <summary> /// Gather information on all classes, interfaces and structs /// Perform code analysis to find scenarios that are erroneous in Windows Runtime</summary> public void FindDiagnostics() { WinRTSyntaxReciever syntaxReciever = (WinRTSyntaxReciever)_context.SyntaxReceiver; if (!syntaxReciever.Declarations.Any()) { Report(WinRTRules.NoPublicTypesRule, null); return; } CheckNamespaces(); CheckDeclarations(); }
public void Generate() { if (CatchWinRTDiagnostics()) { Logger.Log("Exiting early -- found errors in authored runtime component."); Logger.Close(); return; } try { context.AddSource("System.Runtime.InteropServices.WindowsRuntime", SourceText.From(ArrayAttributes, Encoding.UTF8)); string assembly = context.GetAssemblyName(); string version = context.GetAssemblyVersion(); MetadataBuilder metadataBuilder = new MetadataBuilder(); var writer = new WinRTTypeWriter( assembly, version, metadataBuilder, Logger); WinRTSyntaxReciever syntaxReciever = (WinRTSyntaxReciever)context.SyntaxReceiver; Logger.Log("Found " + syntaxReciever.Declarations.Count + " types"); foreach (var declaration in syntaxReciever.Declarations) { writer.Model = context.Compilation.GetSemanticModel(declaration.SyntaxTree); writer.Visit(declaration); } writer.FinalizeGeneration(); GenerateWinMD(metadataBuilder); GenerateSources(); } catch (Exception e) { Logger.Log(e.ToString()); if (e.InnerException != null) { Logger.Log(e.InnerException.ToString()); } Logger.Close(); throw; } Logger.Log("Done"); Logger.Close(); }
private void CheckNamespaces() { WinRTSyntaxReciever syntaxReciever = (WinRTSyntaxReciever)_context.SyntaxReceiver; // Used to check for conflicitng namespace names HashSet <string> namespaceNames = new(); foreach (var @namespace in syntaxReciever.Namespaces) { var model = _context.Compilation.GetSemanticModel(@namespace.SyntaxTree); var namespaceSymbol = model.GetDeclaredSymbol(@namespace); string namespaceString = namespaceSymbol.ToString(); bool newNamespaceDeclaration = true; // Because modules could have a namespace defined in different places (i.e. defines a partial class) // we can't rely on `Contains` so we manually check that namespace names cannot differ by case only foreach (var usedNamespaceName in namespaceNames) { if (String.Equals(namespaceString, usedNamespaceName, StringComparison.OrdinalIgnoreCase) && !String.Equals(namespaceString, usedNamespaceName, StringComparison.Ordinal)) { newNamespaceDeclaration = false; Report(WinRTRules.NamespacesDifferByCase, namespaceSymbol.Locations.First(), namespaceString); } } if (newNamespaceDeclaration) { namespaceNames.Add(namespaceString); } if (IsInvalidNamespace(namespaceSymbol, _assemblyName)) { Report(WinRTRules.DisjointNamespaceRule, namespaceSymbol.Locations.First(), _assemblyName, namespaceString); } } }
private void CheckDeclarations() { WinRTSyntaxReciever syntaxReciever = (WinRTSyntaxReciever)_context.SyntaxReceiver; foreach (var declaration in syntaxReciever.Declarations) { var model = _context.Compilation.GetSemanticModel(declaration.SyntaxTree); // Check symbol information for whether it is public to properly detect partial types // which can leave out modifier. if (model.GetDeclaredSymbol(declaration).DeclaredAccessibility != Accessibility.Public) { continue; } if (declaration is ClassDeclarationSyntax @class) { var classId = @class.Identifier; var classSymbol = model.GetDeclaredSymbol(@class); var publicMethods = @class.ChildNodes().OfType <MethodDeclarationSyntax>().Where(IsPublic); var props = @class.DescendantNodes().OfType <PropertyDeclarationSyntax>().Where(IsPublic); // filter out methods and properties that will be replaced with our custom type mappings IgnoreCustomTypeMappings(classSymbol, ref publicMethods, ref props); if (!classSymbol.IsSealed && !classSymbol.IsStatic) { Report(WinRTRules.UnsealedClassRule, @class.GetLocation(), classId); } OverloadsOperator(@class); HasMultipleConstructorsOfSameArity(@class); if (classSymbol.IsGenericType) { Report(WinRTRules.GenericTypeRule, @class.GetLocation(), classId); } // check for things in nonWindowsRuntimeInterfaces ImplementsInvalidInterface(classSymbol, @class); CheckProperties(props, classId); // check types -- todo: check for !valid types CheckMethods(publicMethods, classId); } else if (declaration is InterfaceDeclarationSyntax @interface) { var interfaceSym = model.GetDeclaredSymbol(@interface); var methods = @interface.DescendantNodes().OfType <MethodDeclarationSyntax>(); var props = @interface.DescendantNodes().OfType <PropertyDeclarationSyntax>().Where(IsPublic); // filter out methods and properties that will be replaced with our custom type mappings IgnoreCustomTypeMappings(interfaceSym, ref methods, ref props); if (interfaceSym.IsGenericType) { Report(WinRTRules.GenericTypeRule, @interface.GetLocation(), @interface.Identifier); } ImplementsInvalidInterface(interfaceSym, @interface); CheckProperties(props, @interface.Identifier); CheckMethods(methods, @interface.Identifier); } else if (declaration is StructDeclarationSyntax @struct) { CheckStructFields(@struct); } } }