diff --git a/Rubberduck.Parsing/VBA/DeclarationCaching/DeclarationFinder.cs b/Rubberduck.Parsing/VBA/DeclarationCaching/DeclarationFinder.cs index 2ff6140f94..2df8eba7d9 100644 --- a/Rubberduck.Parsing/VBA/DeclarationCaching/DeclarationFinder.cs +++ b/Rubberduck.Parsing/VBA/DeclarationCaching/DeclarationFinder.cs @@ -1302,7 +1302,8 @@ public IEnumerable FindNewDeclarationNameConflicts(string newName, return Enumerable.Empty(); } - var identifierMatches = MatchName(newName).ToList(); + var identifierMatches = MatchName(newName).Where(match => match.ProjectId == renameTarget.ProjectId); + if (!identifierMatches.Any()) { return Enumerable.Empty(); @@ -1327,7 +1328,7 @@ public IEnumerable FindNewDeclarationNameConflicts(string newName, || idm.DeclarationType.HasFlag(DeclarationType.Variable) && idm.ParentDeclaration.DeclarationType.HasFlag(DeclarationType.Module) && renameTarget.References.Any(renameTargetRef => renameTargetRef.QualifiedModuleName == idm.ParentDeclaration.QualifiedModuleName)) - .ToList(); + .ToList(); if (referenceConflicts.Any()) { @@ -1342,7 +1343,8 @@ public IEnumerable FindNewDeclarationNameConflicts(string newName, renameTargetModule, renameTarget.ParentDeclaration, idm) - && IsConflictingMember(renameTarget, renameTargetModule, idm)); + && IsConflictingMember(renameTarget, renameTargetModule, idm)) + .ToList(); return declarationConflicts; } diff --git a/RubberduckTests/Symbols/DeclarationFinderTests.cs b/RubberduckTests/Symbols/DeclarationFinderTests.cs index 76f324e043..dd7ea42892 100644 --- a/RubberduckTests/Symbols/DeclarationFinderTests.cs +++ b/RubberduckTests/Symbols/DeclarationFinderTests.cs @@ -12,6 +12,7 @@ using Rubberduck.Common; using Rubberduck.Parsing; using Rubberduck.Parsing.Grammar; +using System; namespace RubberduckTests.Symbols { @@ -445,6 +446,45 @@ End Sub Assert.AreEqual(isConflict, conflicts.Where(cf => cf.IdentifierName.Equals(nameToCheck)).Any(), ConflictMessage(isConflict, nameToCheck, conflicts)); } + + //https://github.com/rubberduck-vba/Rubberduck/issues/4969 + private const string projectOneModuleName = "projectOneModule"; + private const string projectTwoModuleName = "projectTwoModule"; + [TestCase(projectOneModuleName, 0)] //Duplicate module name found in a separate project + [TestCase(projectTwoModuleName, 1)] //Duplicate module name found in the same project + [Category("Resolver")] + public void DeclarationFinder_NameConflictDetectionRespectsProjectScope(string proposedTestModuleName, int expectedCount) + { + + string renameTargetModuleName = "TargetModule"; + + string moduleContent = $"Private Sub Foo(){Environment.NewLine}End Sub"; + + var projectOneContent = new TestComponentSpecification[] + { + new TestComponentSpecification(projectOneModuleName, moduleContent, ComponentType.StandardModule) + }; + + var projectTwoContent = new TestComponentSpecification[] + { + new TestComponentSpecification(renameTargetModuleName, moduleContent, ComponentType.StandardModule), + new TestComponentSpecification(projectTwoModuleName, moduleContent, ComponentType.StandardModule) + }; + + var vbe = BuildProjects(new (string, IEnumerable)[] + {("ProjectOne", projectOneContent),("ProjectTwo", projectTwoContent)}); + + using(var parser = MockParser.CreateAndParse(vbe)) + { + var target = parser.DeclarationFinder.UserDeclarations(DeclarationType.ProceduralModule) + .FirstOrDefault(item => item.IdentifierName.Equals(renameTargetModuleName)); + + var results = parser.DeclarationFinder.FindNewDeclarationNameConflicts(proposedTestModuleName, target); + + Assert.AreEqual(expectedCount, results.Count()); + } + } + private static string ConflictMessage(bool isConflict, string name, IEnumerable conflicts) { return isConflict ? $"Identifier '{name}' is a conflict but was not identified" : $"Identifier '{name}' was incorrectly found as a conflict"; @@ -498,14 +538,33 @@ private void AddTestComponent(AccessibilityTestsDataObject tdo, string moduleIde } private IVBE BuildProject(string projectName, List testComponents) + { + var projectDefs = new (string, IEnumerable)[] { (projectName, testComponents) }; + return BuildProjects(projectDefs); + } + + private IVBE BuildProjects(IEnumerable<(string ProjectName, IEnumerable TestComponents)> projectDefinitions) { var builder = new MockVbeBuilder(); + foreach (var projectDef in projectDefinitions) + { + builder = AddProject(builder, projectDef.ProjectName, projectDef.TestComponents); + } + return builder.Build().Object; + } + + private MockVbeBuilder AddProject(MockVbeBuilder builder, string projectName, IEnumerable testComponents) + { var enclosingProjectBuilder = builder.ProjectBuilder(projectName, ProjectProtection.Unprotected); - testComponents.ForEach(c => enclosingProjectBuilder.AddComponent(c.Name, c.ModuleType, c.Content)); + foreach (var testComponent in testComponents) + { + enclosingProjectBuilder.AddComponent(testComponent.Name, testComponent.ModuleType, testComponent.Content); + } + var enclosingProject = enclosingProjectBuilder.Build(); builder.AddProject(enclosingProject); - return builder.Build().Object; + return builder; } private IVBComponent RetrieveComponent(AccessibilityTestsDataObject tdo, string componentName)