Ejemplo n.º 1
0
        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;
        }
Ejemplo n.º 2
0
        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();
            }
        }