public void Initialize(CoreSupportedMethodsContainer coreSupportedMethods, string supportedElementsPath) { _coreSupportedMethods = coreSupportedMethods; // Add additional supported methods that are not defined in the proxies (such as "Int32.Parse"): foreach (Tuple <string, List <string> > typeToMethods in GetSupportedMethods(supportedElementsPath)) { HashSet <string> typeMethods = GetReferenceToListOfSupportedMethodsForAGivenTypeName(typeToMethods.Item1); foreach (string methodName in typeToMethods.Item2) { typeMethods.Add(methodName); } } _initialized = true; }
private void Button_Click(object sender, RoutedEventArgs e) { string coreAssemblyPath = CoreAssemblyPathTextBox.Text; string supportedElementsPath = SupportedElementsPathTextBox.Text; string mscorlibFolderPath = MscorlibFolderPathTextBox.Text; string sdkFolderPath = SDKFolderPathTextBox.Text; string otherFoldersPath = OtherFoldersPathTextBox.Text; HashSet <string> xamlFilesToIgnore = null; try { xamlFilesToIgnore = new HashSet <string>(XamlFilesToIgnoreTextBox.Text.Split(',').Select(s => s.Trim().ToLower())); } catch (Exception ex) { MessageBox.Show("Invalid list of XAML files to exclude." + Environment.NewLine + Environment.NewLine + ex.ToString()); return; } if (string.IsNullOrEmpty(coreAssemblyPath) || string.IsNullOrEmpty(supportedElementsPath) || string.IsNullOrEmpty(mscorlibFolderPath)) { MessageBox.Show("Please fill all the fields before continuing."); return; } if (!File.Exists(supportedElementsPath)) { MessageBox.Show("File not found: " + supportedElementsPath); return; } var featuresAndEstimationsFileProcessor = new FeaturesAndEstimationsFileProcessor(FeaturesAndEstimationsPathTextBox.Text); // Save the content of the text boxes for reuse when relaunching the application: SaveContentOfTextBoxes(); #if ASK_USER_TO_CHOOSE_ASSEMBLIES_TO_ANALYZE // Create OpenFileDialog Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog(); // Set filter for file extension and default file extension dlg.DefaultExt = ".dll"; dlg.Filter = "Assemblies and executables (*.dll,*.exe)|*.dll;*.exe"; dlg.Multiselect = true; // Display OpenFileDialog by calling ShowDialog method Nullable <bool> result = dlg.ShowDialog(); if (result == true) { string[] fileNames = dlg.FileNames; #else string[] fileNames = Configuration.AssembliesToAnalyze; if (true) { #endif if (_coreSupportedMethods == null) { _coreSupportedMethods = new CoreSupportedMethodsContainer(coreAssemblyPath); } var logger = new LoggerThatAggregatesAllErrors(); var watch = Stopwatch.StartNew(); var listOfUnsupportedMethods = new List <UnsupportedMethodInfo>(); // Get the path of the folder where the first assembly is located, and add that path to the list of places where to look in for resolving referenced assemblies: string firstFileToAnalyze = fileNames.FirstOrDefault(); string additionalFolderWhereToResolveAssemblies = null; if (firstFileToAnalyze != null) { additionalFolderWhereToResolveAssemblies = System.IO.Path.GetDirectoryName(firstFileToAnalyze); } // Do the analysis: try { foreach (var filename in fileNames) { CompatibilityAnalyzer.Analyze( filename, logger, listOfUnsupportedMethods, _coreSupportedMethods, fileNames, Configuration.UrlNamespacesThatBelongToUserCode, Configuration.AttributesToIgnoreInXamlBecauseTheyAreFromBaseClasses, xamlFilesToIgnore, supportedElementsPath, mscorlibFolderPath, sdkFolderPath, otherFoldersPath, skipTypesWhereNoMethodIsActuallyCalled: true, additionalFolderWhereToResolveAssemblies: additionalFolderWhereToResolveAssemblies);; } } catch (Exception ex) { MessageBox.Show(ex.ToString()); } // Replace all telerik assembly names with "http://schemas.telerik.com/2008/xaml/presentation" so as to avoid differences between namespaces from .xaml files and namespaces from .cs files: foreach (UnsupportedMethodInfo unsupportedMethodInfo in listOfUnsupportedMethods) { if (unsupportedMethodInfo.MethodAssemblyName.StartsWith("Telerik.")) { unsupportedMethodInfo.MethodAssemblyName = "http://schemas.telerik.com/2008/xaml/presentation"; } } // Replace all Expression Blend-related namespaces with "http://schemas.microsoft.com/expression/2010/..." so as to avoid differences between namespaces from .xaml files and namespaces from .cs files: foreach (UnsupportedMethodInfo unsupportedMethodInfo in listOfUnsupportedMethods) { if (unsupportedMethodInfo.MethodAssemblyName.StartsWith("Microsoft.Expression.") || unsupportedMethodInfo.MethodAssemblyName.StartsWith("System.Windows.Interactivity") || unsupportedMethodInfo.MethodAssemblyName == "http://schemas.microsoft.com/expression/2010/drawing" || unsupportedMethodInfo.MethodAssemblyName == "http://schemas.microsoft.com/expression/2010/interactivity" || unsupportedMethodInfo.MethodAssemblyName == "http://schemas.microsoft.com/expression/2010/interactions" ) { unsupportedMethodInfo.MethodAssemblyName = "http://schemas.microsoft.com/expression/2010/..."; } } // Aggregate all MEF-related namespaces: foreach (UnsupportedMethodInfo unsupportedMethodInfo in listOfUnsupportedMethods) { if (unsupportedMethodInfo.MethodAssemblyName.StartsWith("System.ComponentModel.Composition.")) { unsupportedMethodInfo.MethodAssemblyName = "System.ComponentModel.Composition"; } } // Aggregate all DomainServices-related namespaces: foreach (UnsupportedMethodInfo unsupportedMethodInfo in listOfUnsupportedMethods) { if (unsupportedMethodInfo.MethodAssemblyName.StartsWith("System.ServiceModel.DomainServices.Client.")) { unsupportedMethodInfo.MethodAssemblyName = "System.ServiceModel.DomainServices.Client"; } } // Replace all the native MS UI-related assembly names with "http://schemas.microsoft.com/winfx/2006/xaml/presentation" so as to avoid differences between namespaces from .xaml files and namespaces from .cs files: foreach (UnsupportedMethodInfo unsupportedMethodInfo in listOfUnsupportedMethods) { if (unsupportedMethodInfo.MethodAssemblyName == "System.Windows" || unsupportedMethodInfo.MethodAssemblyName == "System.Windows.Controls" || unsupportedMethodInfo.MethodAssemblyName == "System.Windows.Controls.Data" || unsupportedMethodInfo.MethodAssemblyName == "System.Windows.Browser" || unsupportedMethodInfo.MethodAssemblyName == "System.Windows.Controls.Navigation" || unsupportedMethodInfo.MethodAssemblyName == "System.Windows.Controls.Toolkit") { unsupportedMethodInfo.MethodAssemblyName = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; } } // Process the list of unsupported methods: SortedDictionary <Tuple <string, string>, HashSet <string> > unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed; ProcessUnsupportedMethods(listOfUnsupportedMethods, out unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed, rectifyMethodName: true); // Remove some stuff: foreach (Tuple <string, string> additionalEntryToRemove in Configuration.AdditionalEntriesToRemoveBeforeAggregation) { unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed.Remove(additionalEntryToRemove); } // For classes that are not defined at all (ie. missing constructor), aggregate all the methods into the same line: List <Tuple <string, string> > entriesToRemoveFromDictionary = new List <Tuple <string, string> >(); // This is here because we cannot remove the keys while iterating in the dictionary, so we do it afterwards. List <KeyValuePair <Tuple <string, string>, HashSet <string> > > entriesToAddToDictionary = new List <KeyValuePair <Tuple <string, string>, HashSet <string> > >(); // This is here because we cannot add entries while iterating in the dictionary, so we do it afterwards. HashSet <Tuple <string, string> > classesForWhichTheMethodsHaveAlreadyBeenAggregated = new HashSet <Tuple <string, string> >(); foreach (KeyValuePair <Tuple <string, string>, HashSet <string> > pair in unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed) { string theFullMethodName = pair.Key.Item1; string theAssemblyName = pair.Key.Item2; HashSet <string> whereItIsUsed = pair.Value; if (!Configuration.EntriesToNotAggregateWithOtherEntries.Contains(theFullMethodName)) { #if ALWAYS_AGGREGATE_METHODS if (theFullMethodName.Contains(".")) #else if (theFullMethodName.Contains("..ctor")) #endif { #if ALWAYS_AGGREGATE_METHODS string className = theFullMethodName.Substring(0, theFullMethodName.IndexOf(".")); #else string className = theFullMethodName.Substring(0, theFullMethodName.IndexOf("..ctor")); #endif if (!classesForWhichTheMethodsHaveAlreadyBeenAggregated.Contains(new Tuple <string, string>(className, theAssemblyName))) { classesForWhichTheMethodsHaveAlreadyBeenAggregated.Add(new Tuple <string, string>(className, theAssemblyName)); List <string> methodNames = new List <string>(); // Find all other methods that concern the same class: foreach (KeyValuePair <Tuple <string, string>, HashSet <string> > pair2 in unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed) { //todo-perf: optimize performance by creating a dictionary beforehand instead of nesting two iterations! string theFullMethodName2 = pair2.Key.Item1; string theAssemblyName2 = pair2.Key.Item2; HashSet <string> whereItIsUsed2 = pair.Value; if (!Configuration.EntriesToNotAggregateWithOtherEntries.Contains(theFullMethodName2)) { if (theFullMethodName2.Contains('.') && !theFullMethodName2.Contains("..ctor") ) { string className2 = theFullMethodName2.Substring(0, theFullMethodName2.IndexOf('.')); if (className2 == className && theAssemblyName2 == theAssemblyName) { string methodName2 = theFullMethodName2.Substring(theFullMethodName2.IndexOf('.') + 1); methodNames.Add(methodName2); HashSetHelpers.AddItemsFromOneHashSetToAnother(whereItIsUsed2, whereItIsUsed); entriesToRemoveFromDictionary.Add(pair2.Key); } } } } // Aggregate them: string newMethodName; if (methodNames.Count > 0) { if (theFullMethodName.Contains("..ctor")) { newMethodName = className + " (members used: " + string.Join(", ", methodNames) + ")"; } else { newMethodName = className + "." + string.Join(", .", methodNames); } } else { newMethodName = className; } entriesToRemoveFromDictionary.Add(pair.Key); entriesToAddToDictionary.Add(new KeyValuePair <Tuple <string, string>, HashSet <string> >( new Tuple <string, string>(newMethodName, theAssemblyName), whereItIsUsed)); } } } } // Perform the actual removal and addition (note: this cannot be done before because it is not possible to remove or add an item from a collection while iterating it with "foreach"); foreach (var key in entriesToRemoveFromDictionary) { unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed.Remove(key); } foreach (var entry in entriesToAddToDictionary) { unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed.Add(entry.Key, entry.Value); } //------------------------------------- // Merge classes that are related to each other: //------------------------------------- MergingRelatedClasses.MergeRelatedClasses(Configuration.ClassesRelatedToEachOther, unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed); //------------------------------------- // Remove elements with an empty assembly name because they are due to "clr-namespace:..." without any assembly being specified, which means that the assembly is the user assembly itself, so we should remove the entry: //------------------------------------- entriesToRemoveFromDictionary = new List <Tuple <string, string> >(); foreach (var entry in unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed) { if (entry.Key.Item2 == "") { entriesToRemoveFromDictionary.Add(entry.Key); } } foreach (var key in entriesToRemoveFromDictionary) { unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed.Remove(key); } //------------------------------------- // Remove some additional stuff: //------------------------------------- foreach (Tuple <string, string> additionalEntryToRemove in Configuration.AdditionalEntriesToRemoveAfterAggregation) { unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed.Remove(additionalEntryToRemove); } //------------------------------------- // Save the result: //------------------------------------- // Save as Excel document: ExcelGenerator.Generate( OutputExcelFilePathTextBox.Text, featuresAndEstimationsFileProcessor, unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed, fileNames.Select(fileName => System.IO.Path.GetFileName(fileName))); #if SAVE_CSV_DOCUMENT // Save as CSV document: CsvGenerator.Generate(OutputCsvFilePathTextBox.Text, unsupportedMethodsAndTheirAssemblyToLocationsWhereTheyAreUsed); #endif var elapsedMs = watch.ElapsedMilliseconds; MessageBox.Show(string.Format("Operation completed in {0} seconds.", Math.Floor(elapsedMs / 1000d).ToString())); //------------------------------------- // Open the result: //------------------------------------- Process.Start(OutputExcelFilePathTextBox.Text); //------------------------------------- // Close this app: //------------------------------------- System.Windows.Application.Current.Shutdown(); } }