• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Camelcade / Perl5-IDEA / #525521635

20 Jul 2025 03:45PM UTC coverage: 82.266% (-0.09%) from 82.355%
#525521635

push

github

hurricup
Build 252.23892.248

30936 of 37605 relevant lines covered (82.27%)

0.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.0
/plugin/backend/src/main/java/com/perl5/lang/pod/parser/psi/util/PodFileUtil.java
1
/*
2
 * Copyright 2015-2025 Alexandr Evstigneev
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package com.perl5.lang.pod.parser.psi.util;
18

19
import com.intellij.openapi.project.Project;
20
import com.intellij.openapi.util.text.StringUtil;
21
import com.intellij.openapi.vfs.VfsUtilCore;
22
import com.intellij.openapi.vfs.VirtualFile;
23
import com.intellij.psi.PsiFile;
24
import com.intellij.psi.PsiManager;
25
import com.intellij.psi.PsiReference;
26
import com.intellij.psi.search.FilenameIndex;
27
import com.intellij.psi.search.GlobalSearchScope;
28
import com.intellij.psi.util.PsiUtilCore;
29
import com.intellij.util.Processor;
30
import com.perl5.lang.perl.fileTypes.PerlFileTypePackage;
31
import com.perl5.lang.perl.idea.project.PerlProjectManager;
32
import com.perl5.lang.perl.util.PerlPackageUtil;
33
import com.perl5.lang.perl.util.PerlPackageUtilCore;
34
import com.perl5.lang.pod.PodLanguage;
35
import com.perl5.lang.pod.filetypes.PodFileType;
36
import com.perl5.lang.pod.parser.psi.PodLinkDescriptor;
37
import com.perl5.lang.pod.parser.psi.mixin.PodFormatterL;
38
import com.perl5.lang.pod.parser.psi.references.PodLinkToFileReference;
39
import org.jetbrains.annotations.NotNull;
40
import org.jetbrains.annotations.Nullable;
41

42
import java.util.ArrayList;
43
import java.util.List;
44

45
public class PodFileUtil {
×
46
  public static final String PM_OR_POD_EXTENSION_PATTERN = ".(" + PodFileType.EXTENSION + "|" + PerlFileTypePackage.EXTENSION + ")$";
47

48
  public static @Nullable String getPackageName(PsiFile file) {
49
    VirtualFile virtualFile = file.getVirtualFile();
1✔
50
    if (virtualFile == null) {
1✔
51
      return null;
1✔
52
    }
53

54
    var fileExtension = virtualFile.getExtension();
1✔
55
    if (!PodFileType.EXTENSION.equals(fileExtension) && !PerlFileTypePackage.EXTENSION.equals(fileExtension)) {
1✔
56
      return null;
1✔
57
    }
58

59
    VirtualFile classRoot = PerlPackageUtil.getClosestIncRoot(file);
1✔
60
    return classRoot == null ? virtualFile.getName() : getPackageNameFromVirtualFile(virtualFile, classRoot);
1✔
61
  }
62

63
  /**
64
   * Searching perl file related to specified pod file
65
   *
66
   * @param podFile pod psi file
67
   * @return perl psi file if found
68
   */
69
  public static @Nullable PsiFile getTargetPerlFile(PsiFile podFile) {
70
    if (podFile == null) {
1✔
71
      return null;
×
72
    }
73

74
    final PsiFile baseFile = podFile.getViewProvider().getStubBindingRoot();
1✔
75
    if (baseFile != podFile) {
1✔
76
      return baseFile;
1✔
77
    }
78

79
    String packageName = getPackageName(baseFile);
1✔
80
    Project project = baseFile.getProject();
1✔
81
    if (StringUtil.isNotEmpty(packageName)) {
1✔
82
      PsiFile packageFileByName = PerlPackageUtil.getPackagePsiFileByPackageName(project, packageName);
1✔
83
      if (packageFileByName != null) {
1✔
84
        return packageFileByName;
×
85
      }
86
    }
87

88
    VirtualFile baseVirtualFile = PsiUtilCore.getVirtualFile(baseFile);
1✔
89
    if (baseVirtualFile == null) {
1✔
90
      return null;
×
91
    }
92
    VirtualFile containingDirectory = baseVirtualFile.getParent();
1✔
93
    if (containingDirectory == null) {
1✔
94
      return null;
×
95
    }
96
    String neighborPackageFileName = baseVirtualFile.getNameWithoutExtension() + "." + PerlFileTypePackage.EXTENSION;
1✔
97
    VirtualFile neighborPackageFile = containingDirectory.findChild(neighborPackageFileName);
1✔
98
    return neighborPackageFile == null ? null : PsiManager.getInstance(project).findFile(neighborPackageFile);
1✔
99
  }
100

101
  public static @Nullable String getPackageNameFromVirtualFile(VirtualFile file, VirtualFile classRoot) {
102
    String relativePath = VfsUtilCore.getRelativePath(file, classRoot);
1✔
103
    if (relativePath != null) {
1✔
104
      return StringUtil.join(relativePath.replaceAll(PM_OR_POD_EXTENSION_PATTERN, "").split("/"), PerlPackageUtilCore.NAMESPACE_SEPARATOR);
1✔
105
    }
106
    return null;
×
107
  }
108

109
  public static String getFilenameFromPackage(@NotNull String packageName) {
110
    return StringUtil.join(PerlPackageUtilCore.getCanonicalNamespaceName(packageName).split(PerlPackageUtilCore.NAMESPACE_SEPARATOR), "/") +
1✔
111
           "." +
112
           PodFileType.EXTENSION;
113
  }
114

115
  public static @Nullable PsiFile getPodOrPackagePsiByDescriptor(Project project, PodLinkDescriptor descriptor) {
116
    final List<PsiFile> result = new ArrayList<>();
1✔
117

118
    PodFileUtil.processPodFilesByDescriptor(project, descriptor, psiFile -> {
1✔
119
      if (psiFile != null) {
1✔
120
        if (psiFile.getFileType() == PodFileType.INSTANCE) {
1✔
121
          result.clear();
1✔
122
          result.add(psiFile);
1✔
123
          return false;
1✔
124
        }
125
        else if ((psiFile = psiFile.getViewProvider().getPsi(PodLanguage.INSTANCE)) != null) {
1✔
126
          result.add(psiFile);
1✔
127
        }
128
      }
129
      return true;
1✔
130
    });
131

132
    return result.isEmpty() ? null : result.getFirst();
1✔
133
  }
134

135
  public static void processPodFilesByDescriptor(@NotNull Project project,
136
                                                 @NotNull PodLinkDescriptor descriptor,
137
                                                 @NotNull Processor<? super PsiFile> processor) {
138
    if (descriptor.getName() == null) {
1✔
139
      return;
×
140
    }
141
    // seek file
142
    String fileId = descriptor.getName();
1✔
143

144
    final PsiManager psiManager = PsiManager.getInstance(project);
1✔
145
    if (fileId.contains(PerlPackageUtilCore.NAMESPACE_SEPARATOR) ||
1✔
146
        !StringUtil.startsWith(fileId, "perl")) { // can be Foo/Bar.pod or Foo/Bar.pm
1✔
147
      String podRelativePath = PodFileUtil.getFilenameFromPackage(fileId);
1✔
148
      String packageRelativePath = PerlPackageUtilCore.getPackagePathByName(fileId);
1✔
149

150
      for (VirtualFile classRoot : PerlProjectManager.getInstance(project).getAllLibraryRoots()) {
1✔
151
        VirtualFile targetVirtualFile = classRoot.findFileByRelativePath(podRelativePath);
1✔
152
        if (targetVirtualFile != null) {
1✔
153
          if (!processor.process(psiManager.findFile(targetVirtualFile))) {
1✔
154
            return;
1✔
155
          }
156
        }
157

158
        targetVirtualFile = classRoot.findFileByRelativePath(packageRelativePath);
1✔
159
        if (targetVirtualFile != null) {
1✔
160
          if (!processor.process(psiManager.findFile(targetVirtualFile))) {
1✔
161
            return;
×
162
          }
163
        }
164
      }
1✔
165
    }
1✔
166
    else { // top level file perl.*
167
      fileId += "." + PodFileType.EXTENSION;
1✔
168

169
      for (var podFile : FilenameIndex.getVirtualFilesByName(fileId, GlobalSearchScope.allScope(project))) {
1✔
170
        if (!processor.process(psiManager.findFile(podFile))) {
1✔
171
          return;
1✔
172
        }
173
      }
×
174
    }
175
  }
1✔
176

177
  public static @Nullable PsiFile getTargetFile(@NotNull PodFormatterL linkFormatter) {
178
    PsiReference[] references = linkFormatter.getReferences();
1✔
179

180
    for (PsiReference reference : references) {
1✔
181
      if (reference instanceof PodLinkToFileReference) {
1✔
182
        return (PsiFile)reference.resolve();
1✔
183
      }
184
    }
185

186
    return linkFormatter.getContainingFile();
1✔
187
  }
188

189
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc