private void SubscribeToProjectModelUpdates()

in resharper/resharper-unity/src/Unity/Core/Psi/Modules/UnityExternalFilesModuleProcessor.cs [387:445]


        private void SubscribeToProjectModelUpdates()
        {
            // If any of our external files are added to a proper project, remove them from our external files module.
            // Add them back if they're removed from the project model. This can happen if the user generates projects
            // for registry packages, or changes the settings to add .unity or .prefab to projects, or manually edits
            // the project to add the files (although this will get overwritten)
            myChangeManager.Changed.Advise(myLifetime, args =>
            {
                var solutionChanges = args.ChangeMap.GetChanges<SolutionChange>().ToList();
                if (solutionChanges.IsEmpty())
                    return;

                var processedFiles = new HashSet<VirtualFileSystemPath>(); // avoid DEXP-730021 SourceFile is not valid.
                var builder = new PsiModuleChangeBuilder();
                var visitor = new RecursiveProjectModelChangeDeltaVisitor(null, itemChange =>
                {
                    // Only handle changes to files in "real" projects - this means we need to remove our external file,
                    // as it's no longer external to the project. Don't process Misc Files project files - these are
                    // handled automatically by VS, or in response to adding/removing an external PSI file in Rider
                    // (which would lead to an infinite loop).
                    // Note that GetOldProject returns the project the file is being added to, or the project it has
                    // just been removed from
                    // Warning: Removing .Player project should not cause adding file to the ExternalModule 
                    if (itemChange.ProjectItem is IProjectFile projectFile
                        && IsIndexedExternalFile(projectFile.Location))
                    {
                        if ((itemChange.IsAdded || itemChange.IsMovedIn) && !itemChange.ProjectItem.IsMiscProjectItem())
                        {
                            myLogger.Trace(
                                "External Unity file added to project {0}. Removing from external files module: {1}",
                                projectFile.GetProject()?.Name ?? "<null>", projectFile.Location);

                            RemoveExternalPsiSourceFile(builder, projectFile.Location);
                        }
                        else if ((itemChange.IsRemoved || itemChange.IsMovedOut) && itemChange.OldLocation.ExistsFile 
                                 && mySolution.FindProjectItemsByLocation(itemChange.OldLocation).All(t => t.IsMiscProjectItem()))
                        {
                            var isUserEditable = IsUserEditable(itemChange.OldLocation, out var isKnownExternalFile);
                            if (isKnownExternalFile && !processedFiles.Contains(itemChange.OldLocation))
                            {
                                myLogger.Trace(
                                    "External Unity file removed from project {0}. Adding to external files module: {1}",
                                    itemChange.GetOldProject()?.Name ?? "<null>", itemChange.OldLocation);
                                
                                processedFiles.Add(itemChange.OldLocation);
                                AddOrUpdateExternalPsiSourceFile(builder, itemChange.OldLocation,
                                    myProjectFileExtensions.GetFileType(projectFile.Location), isUserEditable);
                            }
                        }
                    }
                });

                foreach (var solutionChange in solutionChanges)
                    solutionChange.Accept(visitor);

                if (!builder.IsEmpty)
                    myChangeManager.ExecuteAfterChange(() => FlushChanges(builder));
            });
        }