protected override IList<FileChange> GetFileChanges() { var fileChangeMap = new Dictionary<string, FileChange>(); using (WaitCursorHelper.NewWaitCursor()) { var artifact = _contributorInput.ObjectToBeRenamed.Artifact; var artifactProjectItem = VsUtils.GetProjectItemForDocument(artifact.Uri.LocalPath, Services.ServiceProvider); if (artifactProjectItem != null) { // Run the custom tool to ensure the generated code is up-to-date VsUtils.RunCustomTool(artifactProjectItem); var generatedCodeProjectItem = VsUtils.GetGeneratedCodeProjectItem(artifactProjectItem); if (generatedCodeProjectItem != null) { var generatedItemPath = generatedCodeProjectItem.get_FileNames(1); var objectSearchLanguage = FileExtensions.VbExt.Equals( Path.GetExtension(generatedItemPath), StringComparison.OrdinalIgnoreCase) ? ObjectSearchLanguage.VB : ObjectSearchLanguage.CSharp; var codeElements = generatedCodeProjectItem.FileCodeModel.CodeElements.OfType<CodeElement2>(); CodeElementRenameData renameData = null; // Check if we're refactoring an EntityType or Property var entityType = _contributorInput.ObjectToBeRenamed as EntityType; var property = _contributorInput.ObjectToBeRenamed as Property; if (entityType != null) { var newEntitySetName = _contributorInput.NewName; var pluralize = ModelHelper.GetDesignerPropertyValueFromArtifactAsBool( OptionsDesignerInfo.ElementName, OptionsDesignerInfo.AttributeEnablePluralization, OptionsDesignerInfo.EnablePluralizationDefault, artifact); // Pluralize the entity set name if the setting it turned on if (pluralize) { var pluralizationService = DependencyResolver.GetService<IPluralizationService>(); newEntitySetName = pluralizationService.Pluralize(_contributorInput.NewName); } renameData = new CodeElementRenameData( _contributorInput.NewName, newEntitySetName, _contributorInput.OldName, entityType.EntitySet.Name.Value); } else if (property != null) { if (property.EntityType != null) { renameData = new CodeElementRenameData( _contributorInput.NewName, _contributorInput.OldName, property.EntityType.Name.Value); } } if (renameData != null) { var codeElementsToRename = new Dictionary<CodeElement2, Tuple<string, string>>(); CodeElementUtilities.FindRootCodeElementsToRename( codeElements, renameData, generatedItemPath, objectSearchLanguage, ref codeElementsToRename); var changeProposals = new List<ChangeProposal>(); // We may need to rename more than one object, as type names affect functions and entity set properties. This means we need to loop through and // process each root item change in the generated code designer file. foreach (var codeElementToRename in codeElementsToRename.Keys) { var nameTuple = codeElementsToRename[codeElementToRename]; CodeElementUtilities.CreateChangeProposals( codeElementToRename, nameTuple.Item1, nameTuple.Item2, generatedItemPath, changeProposals, objectSearchLanguage); } // Now sort the change proposals by filename so that we can return a list of file changes foreach (var changeProposal in changeProposals) { FileChange fileChange; HashSet<ChangeProposal> fileChangeProposals; if (fileChangeMap.TryGetValue(changeProposal.FileName, out fileChange)) { fileChangeProposals = fileChange.ChangeList.Values.First(); } else { fileChange = new FileChange(changeProposal.FileName); fileChangeProposals = new HashSet<ChangeProposal>(); fileChange.ChangeList.Add( new KeyValuePair<RefactoringPreviewGroup, HashSet<ChangeProposal>>( new RefactoringPreviewGroup(Resources.RefactorPreviewGroupName), fileChangeProposals)); fileChangeMap.Add(changeProposal.FileName, fileChange); } if (!fileChangeProposals.Contains(changeProposal)) { fileChangeProposals.Add(changeProposal); } } } } } } return fileChangeMap.Values.ToList(); }
internal static void FindRootCodeElementsToRename( IEnumerable <CodeElement2> codeElements, CodeElementRenameData renameData, string generatedItemPath, ObjectSearchLanguage objectSearchLanguage, ref Dictionary <CodeElement2, Tuple <string, string> > codeElementsToRename) { if (codeElementsToRename == null) { codeElementsToRename = new Dictionary <CodeElement2, Tuple <string, string> >(); } var newName = renameData.NewName; var oldName = renameData.OldName; var targetType = renameData.RefactorTargetType; // Rename the symbols that match the old name foreach (var codeElement in codeElements) { if (codeElement.Kind == vsCMElement.vsCMElementNamespace) { FindRootCodeElementsToRename( codeElement.Children.OfType <CodeElement2>(), renameData, generatedItemPath, objectSearchLanguage, ref codeElementsToRename); } else if (codeElement.Kind == vsCMElement.vsCMElementClass) { if (targetType == RefactorTargetType.Class) { if (codeElement.Name.Equals(oldName, StringComparison.Ordinal)) { codeElementsToRename.Add(codeElement, new Tuple <string, string>(newName, oldName)); } // If we're refactoring a class, we need to iterate another level deeper even if the name of this Type doesn't match what we're refactoring // since we need to rename the AddTo*() functions FindRootCodeElementsToRename( codeElement.Children.OfType <CodeElement2>(), renameData, generatedItemPath, objectSearchLanguage, ref codeElementsToRename); } else if (targetType == RefactorTargetType.Property) { // If we're refactoring a property we need to iterate another level deeper to find the property elements. FindRootCodeElementsToRename( codeElement.Children.OfType <CodeElement2>(), renameData, generatedItemPath, objectSearchLanguage, ref codeElementsToRename); } } else if (codeElement.Kind == vsCMElement.vsCMElementFunction && targetType == RefactorTargetType.Class) { // Functions use the entity set name, so check for pluralization string oldFuncName; string newFuncName; var function = (CodeFunction)codeElement; var parentType = function.Parent as CodeType; var oldFactoryFuncName = string.Format(CultureInfo.InvariantCulture, CreateFuncFormat, oldName); if (parentType != null && parentType.Name.Equals(oldName, StringComparison.Ordinal) && function.Name.Equals(oldFactoryFuncName, StringComparison.Ordinal)) { // We need to rename Create* factory funcs as they use the class name. codeElementsToRename.Add( codeElement, new Tuple <string, string>( string.Format(CultureInfo.InvariantCulture, CreateFuncFormat, newName), oldFactoryFuncName)); } else { // We also need to rename the AddTo* funcs when we rename classes, since the class name is used in the generated func name. oldFuncName = string.Format(CultureInfo.InvariantCulture, AddToFuncFormat, renameData.OldEntitySetName); if (codeElement.Name.Equals(oldFuncName, StringComparison.Ordinal)) { newFuncName = string.Format(CultureInfo.InvariantCulture, AddToFuncFormat, renameData.NewEntitySetName); codeElementsToRename.Add(codeElement, new Tuple <string, string>(newFuncName, oldFuncName)); } } } else if (codeElement.Kind == vsCMElement.vsCMElementProperty) { if (targetType == RefactorTargetType.Property) { if (codeElement.Name.Equals(oldName, StringComparison.Ordinal)) { // Ensure the class name matches as well var splitFullName = codeElement.FullName.Split('.'); if (splitFullName.Length >= 2 && splitFullName[splitFullName.Length - 2].Equals(renameData.ParentEntityTypeName, StringComparison.Ordinal)) { codeElementsToRename.Add(codeElement, new Tuple <string, string>(newName, oldName)); } } } else if (targetType == RefactorTargetType.Class) { // There is a property on the container which contains the entity set. if (codeElement.Name.Equals(renameData.OldEntitySetName, StringComparison.Ordinal)) { codeElementsToRename.Add( codeElement, new Tuple <string, string>(renameData.NewEntitySetName, renameData.OldEntitySetName)); } } } } }
protected override IList <FileChange> GetFileChanges() { var fileChangeMap = new Dictionary <string, FileChange>(); using (WaitCursorHelper.NewWaitCursor()) { var artifact = _contributorInput.ObjectToBeRenamed.Artifact; var artifactProjectItem = VsUtils.GetProjectItemForDocument(artifact.Uri.LocalPath, Services.ServiceProvider); if (artifactProjectItem != null) { // Run the custom tool to ensure the generated code is up-to-date VsUtils.RunCustomTool(artifactProjectItem); var generatedCodeProjectItem = VsUtils.GetGeneratedCodeProjectItem(artifactProjectItem); if (generatedCodeProjectItem != null) { var generatedItemPath = generatedCodeProjectItem.get_FileNames(1); var objectSearchLanguage = FileExtensions.VbExt.Equals( Path.GetExtension(generatedItemPath), StringComparison.OrdinalIgnoreCase) ? ObjectSearchLanguage.VB : ObjectSearchLanguage.CSharp; var codeElements = generatedCodeProjectItem.FileCodeModel.CodeElements.OfType <CodeElement2>(); CodeElementRenameData renameData = null; // Check if we're refactoring an EntityType or Property var entityType = _contributorInput.ObjectToBeRenamed as EntityType; var property = _contributorInput.ObjectToBeRenamed as Property; if (entityType != null) { var newEntitySetName = _contributorInput.NewName; var pluralize = ModelHelper.GetDesignerPropertyValueFromArtifactAsBool( OptionsDesignerInfo.ElementName, OptionsDesignerInfo.AttributeEnablePluralization, OptionsDesignerInfo.EnablePluralizationDefault, artifact); // Pluralize the entity set name if the setting it turned on if (pluralize) { var pluralizationService = DependencyResolver.GetService <IPluralizationService>(); newEntitySetName = pluralizationService.Pluralize(_contributorInput.NewName); } renameData = new CodeElementRenameData( _contributorInput.NewName, newEntitySetName, _contributorInput.OldName, entityType.EntitySet.Name.Value); } else if (property != null) { if (property.EntityType != null) { renameData = new CodeElementRenameData( _contributorInput.NewName, _contributorInput.OldName, property.EntityType.Name.Value); } } if (renameData != null) { var codeElementsToRename = new Dictionary <CodeElement2, Tuple <string, string> >(); CodeElementUtilities.FindRootCodeElementsToRename( codeElements, renameData, generatedItemPath, objectSearchLanguage, ref codeElementsToRename); var changeProposals = new List <ChangeProposal>(); // We may need to rename more than one object, as type names affect functions and entity set properties. This means we need to loop through and // process each root item change in the generated code designer file. foreach (var codeElementToRename in codeElementsToRename.Keys) { var nameTuple = codeElementsToRename[codeElementToRename]; CodeElementUtilities.CreateChangeProposals( codeElementToRename, nameTuple.Item1, nameTuple.Item2, generatedItemPath, changeProposals, objectSearchLanguage); } // Now sort the change proposals by filename so that we can return a list of file changes foreach (var changeProposal in changeProposals) { FileChange fileChange; HashSet <ChangeProposal> fileChangeProposals; if (fileChangeMap.TryGetValue(changeProposal.FileName, out fileChange)) { fileChangeProposals = fileChange.ChangeList.Values.First(); } else { fileChange = new FileChange(changeProposal.FileName); fileChangeProposals = new HashSet <ChangeProposal>(); fileChange.ChangeList.Add( new KeyValuePair <RefactoringPreviewGroup, HashSet <ChangeProposal> >( new RefactoringPreviewGroup(Resources.RefactorPreviewGroupName), fileChangeProposals)); fileChangeMap.Add(changeProposal.FileName, fileChange); } if (!fileChangeProposals.Contains(changeProposal)) { fileChangeProposals.Add(changeProposal); } } } } } } return(fileChangeMap.Values.ToList()); }
internal static void FindRootCodeElementsToRename( IEnumerable<CodeElement2> codeElements, CodeElementRenameData renameData, string generatedItemPath, ObjectSearchLanguage objectSearchLanguage, ref Dictionary<CodeElement2, Tuple<string, string>> codeElementsToRename) { if (codeElementsToRename == null) { codeElementsToRename = new Dictionary<CodeElement2, Tuple<string, string>>(); } var newName = renameData.NewName; var oldName = renameData.OldName; var targetType = renameData.RefactorTargetType; // Rename the symbols that match the old name foreach (var codeElement in codeElements) { if (codeElement.Kind == vsCMElement.vsCMElementNamespace) { FindRootCodeElementsToRename( codeElement.Children.OfType<CodeElement2>(), renameData, generatedItemPath, objectSearchLanguage, ref codeElementsToRename); } else if (codeElement.Kind == vsCMElement.vsCMElementClass) { if (targetType == RefactorTargetType.Class) { if (codeElement.Name.Equals(oldName, StringComparison.Ordinal)) { codeElementsToRename.Add(codeElement, new Tuple<string, string>(newName, oldName)); } // If we're refactoring a class, we need to iterate another level deeper even if the name of this Type doesn't match what we're refactoring // since we need to rename the AddTo*() functions FindRootCodeElementsToRename( codeElement.Children.OfType<CodeElement2>(), renameData, generatedItemPath, objectSearchLanguage, ref codeElementsToRename); } else if (targetType == RefactorTargetType.Property) { // If we're refactoring a property we need to iterate another level deeper to find the property elements. FindRootCodeElementsToRename( codeElement.Children.OfType<CodeElement2>(), renameData, generatedItemPath, objectSearchLanguage, ref codeElementsToRename); } } else if (codeElement.Kind == vsCMElement.vsCMElementFunction && targetType == RefactorTargetType.Class) { // Functions use the entity set name, so check for pluralization string oldFuncName; string newFuncName; var function = (CodeFunction)codeElement; var parentType = function.Parent as CodeType; var oldFactoryFuncName = string.Format(CultureInfo.InvariantCulture, CreateFuncFormat, oldName); if (parentType != null && parentType.Name.Equals(oldName, StringComparison.Ordinal) && function.Name.Equals(oldFactoryFuncName, StringComparison.Ordinal)) { // We need to rename Create* factory funcs as they use the class name. codeElementsToRename.Add( codeElement, new Tuple<string, string>( string.Format(CultureInfo.InvariantCulture, CreateFuncFormat, newName), oldFactoryFuncName)); } else { // We also need to rename the AddTo* funcs when we rename classes, since the class name is used in the generated func name. oldFuncName = string.Format(CultureInfo.InvariantCulture, AddToFuncFormat, renameData.OldEntitySetName); if (codeElement.Name.Equals(oldFuncName, StringComparison.Ordinal)) { newFuncName = string.Format(CultureInfo.InvariantCulture, AddToFuncFormat, renameData.NewEntitySetName); codeElementsToRename.Add(codeElement, new Tuple<string, string>(newFuncName, oldFuncName)); } } } else if (codeElement.Kind == vsCMElement.vsCMElementProperty) { if (targetType == RefactorTargetType.Property) { if (codeElement.Name.Equals(oldName, StringComparison.Ordinal)) { // Ensure the class name matches as well var splitFullName = codeElement.FullName.Split('.'); if (splitFullName.Length >= 2 && splitFullName[splitFullName.Length - 2].Equals(renameData.ParentEntityTypeName, StringComparison.Ordinal)) { codeElementsToRename.Add(codeElement, new Tuple<string, string>(newName, oldName)); } } } else if (targetType == RefactorTargetType.Class) { // There is a property on the container which contains the entity set. if (codeElement.Name.Equals(renameData.OldEntitySetName, StringComparison.Ordinal)) { codeElementsToRename.Add( codeElement, new Tuple<string, string>(renameData.NewEntitySetName, renameData.OldEntitySetName)); } } } } }