Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Honour namespace provider setting on root folder of external package #2274

Merged
merged 3 commits into from
Feb 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Since 2018.1, the version numbers and release cycle match Rider's versions and r
- Rider: Fix display of unprintable characters in console output when debugging batchmode tests ([RIDER-74056](https://youtrack.jetbrains.com/issue/RIDER-74056), [#2265](https://github.com/JetBrains/resharper-unity/pull/2265))
- Rider: Fix performance issue displaying long log issues from Unity ([RIDER-70574](https://youtrack.jetbrains.com/issue/RIDER-70574), [#2270](https://github.com/JetBrains/resharper-unity/pull/2270))
- Rider: Fix showing duplicate project names in Unity Explorer under certain circumstances ([RIDER-67457](https://youtrack.jetbrains.com/issue/RIDER-67457), [#2273](https://github.com/JetBrains/resharper-unity/pull/2273))
- Rider: Fix root folder of an external package ignoring namespace provider setting ([RIDER-65100](https://youtrack.jetbrains.com/issue/RIDER-65100), [#2274)(https://github.com/JetBrains/resharper-unity/pull/2274))



Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using JetBrains.Annotations;
using JetBrains.Diagnostics;
using JetBrains.ProjectModel;
using JetBrains.ProjectModel.Properties;
Expand All @@ -9,22 +8,30 @@
using JetBrains.ReSharper.Psi.Util;
using JetBrains.Util;

#nullable enable

namespace JetBrains.ReSharper.Plugins.Unity.CSharp.Psi.Util
{
[SolutionComponent]
public class ExternalPackageCustomNamespaceProvider : ICustomDefaultNamespaceProvider
{
private static readonly Key<string> ourCalculatedDefaultNamespaceKey = new Key<string>("Unity::ExternalPackage::DefaultNamespace");
private static readonly Key<DefaultNamespace?> ourCalculatedDefaultNamespaceKey = new("Unity::ExternalPackage::DefaultNamespace");

private readonly NamespaceFolderProperty myNamespaceFolderProperty;

public ExternalPackageCustomNamespaceProvider(NamespaceFolderProperty namespaceFolderProperty)
{
myNamespaceFolderProperty = namespaceFolderProperty;
}

public ExpectedNamespaceAndNamespaceChecker CalculateCustomNamespace(IProjectItem projectItem, PsiLanguageType language)
{
var project = projectItem.GetProject().NotNull();
if (!ShouldProvideCustomNamespace(project, projectItem, language))
return new ExpectedNamespaceAndNamespaceChecker(null);

var namespaceFolderProperty = project.GetComponent<NamespaceFolderProperty>();
return new ExpectedNamespaceAndNamespaceChecker(CalculateNamespace(projectItem, language.LanguageService(),
namespaceFolderProperty));
return new ExpectedNamespaceAndNamespaceChecker(CalculateNamespace(projectItem,
language.LanguageService().NotNull("languageService != null")));
}

private static bool ShouldProvideCustomNamespace(IProject project, IProjectItem projectItem, PsiLanguageType language)
Expand All @@ -46,13 +53,13 @@ private static bool ShouldProvideCustomNamespace(IProject project, IProjectItem
if (!defaultNamespace.IsNullOrEmpty())
return false;

// Is the root folder a linked folder, pointing externally to the solution?
// We're only interested in external packages, which we can identify by checking that the immediate child of
// the project is a linked item (it links to an item external to the solution)
var rootFolder = GetRootFolder(projectItem);
return rootFolder?.IsLinked == true;
}

[CanBeNull]
private static IProjectFolder GetRootFolder(IProjectItem projectItem)
private static IProjectFolder? GetRootFolder(IProjectItem projectItem)
{
var projectFolder = projectItem.ParentFolder;
while (projectFolder != null)
Expand All @@ -66,23 +73,21 @@ private static IProjectFolder GetRootFolder(IProjectItem projectItem)
return null;
}

[CanBeNull]
private static string CalculateNamespace([NotNull] IProjectItem item, LanguageService languageService,
NamespaceFolderProperty namespaceFolderProperty)
private string? CalculateNamespace(IProjectItem item, LanguageService languageService)
{
if (item.ParentFolder is IProject && item is IProjectFolder rootFolder)
return CalculateNamespaceForProjectFromRootFolder(item.GetProject(), rootFolder, languageService);
if (item.ParentFolder is IProject project && item is IProjectFolder rootFolder)
return CalculateNamespaceForProjectFromRootFolder(project, rootFolder, languageService);

var parentFolder = item.ParentFolder;
if (parentFolder == null) return null;

var parentNamespace = CalculateNamespace(parentFolder, languageService, namespaceFolderProperty);
var parentNamespace = CalculateNamespace(parentFolder, languageService);
if (parentNamespace == null)
return null;

if (item is IProjectFolder folder)
{
var isNamespaceProvider = namespaceFolderProperty.GetNamespaceFolderProperty(folder);
var isNamespaceProvider = myNamespaceFolderProperty.GetNamespaceFolderProperty(folder);
if (!isNamespaceProvider)
return parentNamespace;
}
Expand All @@ -101,16 +106,20 @@ private static string CalculateNamespace([NotNull] IProjectItem item, LanguageSe
return suffix;
}

[CanBeNull]
private static string CalculateNamespaceForProjectFromRootFolder(
[CanBeNull] IProject project, IProjectFolder rootFolder, LanguageService languageService)
private string? CalculateNamespaceForProjectFromRootFolder(IProject project, IProjectFolder rootFolder,
LanguageService languageService)
{
if (project == null || !rootFolder.IsLinked || rootFolder.Path == null) return null;
if (!rootFolder.IsLinked || rootFolder.Path == null) return null;

var isNamespaceProvider = myNamespaceFolderProperty.GetNamespaceFolderProperty(rootFolder);

// Cache the calculated namespace for the root folder, but make sure it's calculated with the same namespace
// provider state!
var calculatedNamespace = project.GetData(ourCalculatedDefaultNamespaceKey);
if (calculatedNamespace != null)
return calculatedNamespace;
if (calculatedNamespace != null && calculatedNamespace.RootFolderIsNamespaceProvider == isNamespaceProvider)
return calculatedNamespace.RootFolderNamespace;

var rootFolderNamespace = string.Empty;
var location = rootFolder.Path.ReferencedFolderPath;
var packageJsonDirectory = FileSystemUtil.TryGetDirectoryNameOfFileAbove(location, "package.json");
if (packageJsonDirectory != null)
Expand All @@ -127,16 +136,36 @@ private static string CalculateNamespaceForProjectFromRootFolder(
else if (path.StartsWith("Scripts"))
path = path.RemovePrefix("Scripts");

// The user might have excluded the root folder as a namespace provider. If so, skip and reset the flag.
// This means there is no way to exclude folders between the package.json location and the root folder
var skipFirstComponent = !isNamespaceProvider;
foreach (var pathComponent in path.Components)
{
if (skipFirstComponent)
{
skipFirstComponent = false;
continue;
}
var name = NamespaceFolderUtil.MakeValidQualifiedName(pathComponent.ToString(), languageService);
calculatedNamespace = calculatedNamespace.IsNullOrEmpty() ? name : $"{calculatedNamespace}.{name}";
rootFolderNamespace = rootFolderNamespace.IsNullOrEmpty() ? name : $"{rootFolderNamespace}.{name}";
}
}

calculatedNamespace = new DefaultNamespace(rootFolderNamespace, isNamespaceProvider);
project.PutData(ourCalculatedDefaultNamespaceKey, calculatedNamespace);
return calculatedNamespace.RootFolderNamespace;
}

private class DefaultNamespace
{
public readonly string RootFolderNamespace;
public readonly bool RootFolderIsNamespaceProvider;

return calculatedNamespace;
public DefaultNamespace(string rootFolderNamespace, bool rootFolderIsNamespaceProvider)
{
RootFolderNamespace = rootFolderNamespace;
RootFolderIsNamespaceProvider = rootFolderIsNamespaceProvider;
}
}
}
}