summaryrefslogtreecommitdiff
path: root/platform/lang-impl/src/com/intellij/usageView/UsageViewUtil.java
blob: 4dee56707ae0380a1404aabf695dde654f2bb29a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.intellij.usageView;

import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.GeneratedSourcesFilter;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.ElementDescriptionUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.MoveRenameUsageInfo;
import com.intellij.refactoring.util.NonCodeUsageInfo;
import com.intellij.usages.Usage;
import com.intellij.usages.UsageInfo2UsageAdapter;
import com.intellij.usages.UsageView;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

public class UsageViewUtil {
  private static final Logger LOG = Logger.getInstance("#com.intellij.usageView.UsageViewUtil");

  private UsageViewUtil() { }

  public static String createNodeText(PsiElement element) {
    return ElementDescriptionUtil.getElementDescription(element, UsageViewNodeTextLocation.INSTANCE);
  }

  public static String getShortName(final PsiElement psiElement) {
    LOG.assertTrue(psiElement.isValid(), psiElement);
    return ElementDescriptionUtil.getElementDescription(psiElement, UsageViewShortNameLocation.INSTANCE);
  }

  public static String getLongName(final PsiElement psiElement) {
    LOG.assertTrue(psiElement.isValid(), psiElement);
    return ElementDescriptionUtil.getElementDescription(psiElement, UsageViewLongNameLocation.INSTANCE);
  }

  public static String getType(@NotNull PsiElement psiElement) {
    return ElementDescriptionUtil.getElementDescription(psiElement, UsageViewTypeLocation.INSTANCE);
  }

  public static boolean hasNonCodeUsages(UsageInfo[] usages) {
    for (UsageInfo usage : usages) {
      if (usage.isNonCodeUsage) return true;
    }
    return false;
  }

  public static boolean hasUsagesInGeneratedCode(UsageInfo[] usages, Project project) {
    GeneratedSourcesFilter[] filters = GeneratedSourcesFilter.EP_NAME.getExtensions();
    for (UsageInfo usage : usages) {
      VirtualFile file = usage.getVirtualFile();
      if (file != null) {
        for (GeneratedSourcesFilter filter : filters) {
          if (filter.isGeneratedSource(file, project)) {
            return true;
          }
        }
      }
    }

    return false;
  }

  public static boolean hasReadOnlyUsages(UsageInfo[] usages) {
    for (UsageInfo usage : usages) {
      if (!usage.isWritable()) return true;
    }
    return false;
  }

  public static UsageInfo[] removeDuplicatedUsages(@NotNull UsageInfo[] usages) {
    Set<UsageInfo> set = new LinkedHashSet<UsageInfo>(Arrays.asList(usages));

    // Replace duplicates of move rename usage infos in injections from non code usages of master files
    String newTextInNonCodeUsage = null;

    for(UsageInfo usage:usages) {
      if (!(usage instanceof NonCodeUsageInfo)) continue;
      newTextInNonCodeUsage = ((NonCodeUsageInfo)usage).newText;
      break;
    }

    if (newTextInNonCodeUsage != null) {
      for(UsageInfo usage:usages) {
        if (!(usage instanceof MoveRenameUsageInfo)) continue;
        PsiFile file = usage.getFile();

        if (file != null) {
          PsiElement context = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file);
          if (context != null) {

            PsiElement usageElement = usage.getElement();
            if (usageElement == null) continue;

            PsiReference psiReference = usage.getReference();
            if (psiReference == null) continue;

            int injectionOffsetInMasterFile = InjectedLanguageManager.getInstance(usageElement.getProject()).injectedToHost(usageElement, usageElement.getTextOffset());
            TextRange rangeInElement = usage.getRangeInElement();
            assert rangeInElement != null : usage;
            TextRange range = rangeInElement.shiftRight(injectionOffsetInMasterFile);
            PsiFile containingFile = context.getContainingFile();
            if (containingFile == null) continue; //move package to another package
            set.remove(
              NonCodeUsageInfo.create(
                containingFile,
                range.getStartOffset(),
                range.getEndOffset(),
                ((MoveRenameUsageInfo)usage).getReferencedElement(),
                newTextInNonCodeUsage
              )
            );
          }
        }
      }
    }
    return set.toArray(new UsageInfo[set.size()]);
  }

  @NotNull
  public static UsageInfo[] toUsageInfoArray(@NotNull final Collection<? extends UsageInfo> collection) {
    final int size = collection.size();
    return size == 0 ? UsageInfo.EMPTY_ARRAY : collection.toArray(new UsageInfo[size]);
  }

  @NotNull
  public static PsiElement[] toElements(@NotNull UsageInfo[] usageInfos) {
    return ContainerUtil.map2Array(usageInfos, PsiElement.class, new Function<UsageInfo, PsiElement>() {
      @Override
      public PsiElement fun(UsageInfo info) {
        return info.getElement();
      }
    });
  }

  public static void navigateTo(@NotNull UsageInfo info, boolean requestFocus) {
    int offset = info.getNavigationOffset();
    VirtualFile file = info.getVirtualFile();
    Project project = info.getProject();
    FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, file, offset), requestFocus);
  }

  public static Set<UsageInfo> getNotExcludedUsageInfos(final UsageView usageView) {
    Set<Usage> excludedUsages = usageView.getExcludedUsages();

    Set<UsageInfo> usageInfos = new LinkedHashSet<UsageInfo>();
    for (Usage usage : usageView.getUsages()) {
      if (usage instanceof UsageInfo2UsageAdapter && !excludedUsages.contains(usage)) {
        UsageInfo usageInfo = ((UsageInfo2UsageAdapter)usage).getUsageInfo();
        usageInfos.add(usageInfo);
      }
    }
    return usageInfos;
  }

  public static boolean reportNonRegularUsages(UsageInfo[] usages, final Project project) {
    boolean inGeneratedCode = hasUsagesInGeneratedCode(usages, project);
    if (hasNonCodeUsages(usages) || inGeneratedCode) {
      StatusBar statusBar = WindowManager.getInstance().getStatusBar(project);
      if (statusBar != null) {
        statusBar.setInfo(inGeneratedCode ? RefactoringBundle.message("occurrences.found.in.comments.strings.non.java.files.and.generated.code")
                                          : RefactoringBundle.message("occurrences.found.in.comments.strings.and.non.java.files"));
      }
      return true;
    }
    return false;
  }
}