private void DeleteMethodsIfNeeded( IEnumerable <string> typeMethods, DeletionEvaluator deletionEvaluator, IDocument document, ref CompilationUnitSyntax newDocumentRoot, RoslynMethodLister methodLister, ref int methodsDeleted) { if (typeMethods == null || _options.Act == Act.DeleteWholeTypesOnly) { return; } foreach (var method in typeMethods) { bool needToDelete = deletionEvaluator.NeedToDeleteMethod(method); if (needToDelete) { methodsDeleted++; if (_options.Act == Act.Delete && !_options.DryRun) { // Transform the syntax tree of the document and get the root of the new tree newDocumentRoot = DeleteMethod(newDocumentRoot ?? (CompilationUnitSyntax)document.GetSyntaxRoot(), methodLister, deletionEvaluator, method); } } else if (!deletionEvaluator.MethodFoundInWeavedLibs(method) && _options.Verbose) { _logger.Log(string.Format("not found in dlls, skipping {0}", method), displayTime: false); } if (needToDelete || _options.Verbose) { _logger.Log(string.Format("{0} {1}", needToDelete ? "--" : "++", method), displayTime: false); } } }
private static bool NeedToDeleteWholeProperty(RoslynMethodLister methooLister, DeletionEvaluator evaluator, SyntaxNodeWrapper currentMethodNodeFromNewRoot, MethodType methodType) { var prop = (PropertyDeclarationSyntax)currentMethodNodeFromNewRoot.Node; if (prop.HasGetter() && prop.HasSetter()) { MethodType otherAccessorType = methodType == MethodType.PropertyGetter ? MethodType.PropertySetter : MethodType.PropertyGetter; var otherAccessorStr = methooLister.GetMethodDeclarationString(new SyntaxNodeWrapper { MethodType = otherAccessorType, Node = currentMethodNodeFromNewRoot.Node }); bool needToDelete = evaluator.NeedToDeleteMethod(otherAccessorStr); return(needToDelete); } return(true); }
public void RunCleanup() { int typeCount = 0; int methodCount = 0; int typesDeleted = 0; int methodsDeleted = 0; string action = _options.DryRun ? "to be deleted" : "deleted"; var methodLister = new RoslynMethodLister(_options.PathToSolution, _options.ProjectIncludeFilter, _options.ProjectExcludeFilter, _options.NamespaceFilter); var deletionEvaluator = new DeletionEvaluator(new CodeCleanupRepository(msg => _logger.Log(msg)), new WeawingDataProvider(_options.WeavedLibsDir, msg => _logger.Log(msg))); var filesToDelete = new HashSet <string>(); methodLister.ProcessCSharpSolutionDocuments( (latestForkedSolution, document, root) => { // don't perform deletion in designer files since their content depends on parent files (like dbml or aspx). Cleaner doesn't deal with dbml or aspx/ascx content, it processes only classes if (document.FilePath.EndsWith(".designer.cs", StringComparison.OrdinalIgnoreCase)) { return(null); } _logger.Log(string.Format("\r\n\r\nProcessing document {0} \r\n", document.FilePath)); if (_filesToExcludeBySubstring.Any(document.FilePath.ToLower().Contains)) { _logger.Log(string.Format("Skipping processing (matches fileExcludeFilter) {0} \r\n", document.FilePath)); return(null); } var typeNames = GetDocumentClassesAndStructs(document); var stringifiedMethods = methodLister.GetDocumentMethodStrings(document).ToArray(); methodCount += stringifiedMethods.Length; var methodsGroupedByType = stringifiedMethods.GroupBy(Stringifier.GetTypePart).ToArray(); CompilationUnitSyntax newDocumentRoot = null; int typesDeletedFromDocumentCount = 0; foreach (var typeName in typeNames) { typeCount++; var typeMethods = methodsGroupedByType.FirstOrDefault(g => g.Key == typeName); if (deletionEvaluator.NeedToDeleteType(typeName)) { DeleteType(typeName, action, document, ref newDocumentRoot, typeMethods, ref typesDeleted, ref methodsDeleted); typesDeletedFromDocumentCount++; } else { DeleteMethodsIfNeeded(typeMethods, deletionEvaluator, document, ref newDocumentRoot, methodLister, ref methodsDeleted); } } // 1. delete file and dependent files if no types left in this file (there can be types other than logged, e.g. enums) // 2. for --dryRun the deletion is not actually performed so the condition must be another: number of scheduled for deletion types equals to the number of types in the document var allDocumentTypesCount = GetAllDocumentTypesCount(newDocumentRoot ?? (CompilationUnitSyntax)document.GetSyntaxRoot()); if ((!_options.DryRun && allDocumentTypesCount == 0) || (_options.DryRun && typesDeletedFromDocumentCount == allDocumentTypesCount)) { ScheduleFilesToDelete(filesToDelete, document); } // if the document was modified (types or methods deleted) if (newDocumentRoot != null) { latestForkedSolution = latestForkedSolution.UpdateDocument(document.Id, newDocumentRoot); return(latestForkedSolution); } return(null); }); if (!_options.DryRun) { DeleteFiles(_options.PathToSolution, methodLister, filesToDelete); } _logger.Log(string.Format("\r\n\r\n\r\n\r\nPROCESSING COMPLETED. Total type count = {0}; Types {1} = {2};. Total method count = {3}; Methods {1} = {4};\r\n", typeCount, action, typesDeleted, methodCount, methodsDeleted)); }
private static CompilationUnitSyntax DeleteMethod(CompilationUnitSyntax originalRoot, RoslynMethodLister methodLister, DeletionEvaluator evaluator, string method) { // needs for second and subsequent deletions from one document (cuz the document allways different). var currentMethodNodeFromNewRoot = methodLister.FindInDoc(originalRoot, method); // property deletion - currently implemented only whole property deletion. Separate accessor deletion requires string manipulation since there is no separate syntax node for getter/setter (only AccessorList for both) var methodType = currentMethodNodeFromNewRoot.MethodType; if ((methodType == MethodType.PropertyGetter || methodType == MethodType.PropertySetter) && !NeedToDeleteWholeProperty(methodLister, evaluator, currentMethodNodeFromNewRoot, methodType)) { return(originalRoot); } return(RemoveNode(originalRoot, currentMethodNodeFromNewRoot.Node)); }