update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / psi / impl / source / codeStyle / ImportHelper.java
blob4827da7d6e5c2067b32822664866b4b6f4cab1d8
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.psi.impl.source.codeStyle;
18 import com.intellij.lang.ASTNode;
19 import com.intellij.lang.StdLanguages;
20 import com.intellij.openapi.diagnostic.Logger;
21 import com.intellij.openapi.fileTypes.StdFileTypes;
22 import com.intellij.openapi.util.Comparing;
23 import com.intellij.psi.*;
24 import com.intellij.psi.codeStyle.CodeStyleManager;
25 import com.intellij.psi.codeStyle.CodeStyleSettings;
26 import com.intellij.psi.codeStyle.CodeStyleSettings.ImportLayoutTable;
27 import com.intellij.psi.codeStyle.CodeStyleSettings.ImportLayoutTable.EmptyLineEntry;
28 import com.intellij.psi.codeStyle.CodeStyleSettings.ImportLayoutTable.Entry;
29 import com.intellij.psi.codeStyle.CodeStyleSettings.ImportLayoutTable.PackageEntry;
30 import com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl;
31 import com.intellij.psi.impl.source.SourceTreeToPsiMap;
32 import com.intellij.psi.impl.source.jsp.jspJava.JspxImportStatement;
33 import com.intellij.psi.impl.source.resolve.ResolveClassUtil;
34 import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReference;
35 import com.intellij.psi.jsp.JspFile;
36 import com.intellij.psi.jsp.JspSpiUtil;
37 import com.intellij.psi.search.GlobalSearchScope;
38 import com.intellij.psi.search.LocalSearchScope;
39 import com.intellij.psi.search.searches.ReferencesSearch;
40 import com.intellij.util.ArrayUtil;
41 import com.intellij.util.IncorrectOperationException;
42 import gnu.trove.THashSet;
43 import gnu.trove.TObjectIntHashMap;
44 import gnu.trove.TObjectIntProcedure;
45 import org.jetbrains.annotations.NonNls;
46 import org.jetbrains.annotations.NotNull;
48 import java.util.*;
50 public class ImportHelper{
51 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.codeStyle.ImportHelper");
53 private final CodeStyleSettings mySettings;
54 @NonNls private static final String JAVA_LANG_PACKAGE = "java.lang";
56 public ImportHelper(@NotNull CodeStyleSettings settings){
57 mySettings = settings;
60 public PsiImportList prepareOptimizeImportsResult(@NotNull final PsiJavaFile file) {
61 CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(file.getProject());
63 final Set<String> namesToImportStaticly = new THashSet<String>();
64 String[] names = collectNamesToImport(file, namesToImportStaticly); // Note: this array may contain "<packageOrClassName>.*" for unresolved imports!
65 Arrays.sort(names);
67 ArrayList<String> namesList = new ArrayList<String>();
68 ImportLayoutTable table = mySettings.IMPORT_LAYOUT_TABLE;
69 if (table != null){
70 int[] entriesForName = ArrayUtil.newIntArray(names.length);
71 for(int i = 0; i < names.length; i++){
72 entriesForName[i] = findEntryIndex(names[i]);
75 Entry[] entries = table.getEntries();
76 for(int i = 0; i < entries.length; i++){
77 Entry entry = entries[i];
78 if (entry instanceof PackageEntry){
79 for(int j = 0; j < names.length; j++){
80 if (entriesForName[j] == i){
81 namesList.add(names[j]);
82 names[j] = null;
88 for (String name : names) {
89 if (name != null) namesList.add(name);
91 names = ArrayUtil.toStringArray(namesList);
93 TObjectIntHashMap<String> packageToCountMap = new TObjectIntHashMap<String>();
94 TObjectIntHashMap<String> classToCountMap = new TObjectIntHashMap<String>();
95 for (String name : names) {
96 String packageOrClassName = getPackageOrClassName(name);
97 if (packageOrClassName.length() == 0) continue;
98 if (namesToImportStaticly.contains(name)) {
99 int count = classToCountMap.get(packageOrClassName);
100 classToCountMap.put(packageOrClassName, count + 1);
102 else {
103 int count = packageToCountMap.get(packageOrClassName);
104 packageToCountMap.put(packageOrClassName, count + 1);
108 final Set<String> classesOrPackagesToImportOnDemand = new THashSet<String>();
109 class MyVisitorProcedure implements TObjectIntProcedure<String> {
110 private final boolean myIsVisitingPackages;
112 MyVisitorProcedure(boolean isVisitingPackages) {
113 myIsVisitingPackages = isVisitingPackages;
116 public boolean execute(final String packageOrClassName, final int count) {
117 if (isToUseImportOnDemand(packageOrClassName, count, !myIsVisitingPackages)){
118 classesOrPackagesToImportOnDemand.add(packageOrClassName);
120 return true;
123 classToCountMap.forEachEntry(new MyVisitorProcedure(false));
124 packageToCountMap.forEachEntry(new MyVisitorProcedure(true));
126 Set<String> classesToUseSingle = findSingleImports(file, names, classesOrPackagesToImportOnDemand, namesToImportStaticly);
128 try {
129 final String text = buildImportListText(names, classesOrPackagesToImportOnDemand, classesToUseSingle, namesToImportStaticly);
130 String ext = StdFileTypes.JAVA.getDefaultExtension();
131 final PsiJavaFile dummyFile = (PsiJavaFile)PsiFileFactory.getInstance(file.getProject())
132 .createFileFromText("_Dummy_." + ext, StdFileTypes.JAVA, text);
133 codeStyleManager.reformat(dummyFile);
135 PsiImportList resultList = dummyFile.getImportList();
136 PsiImportList oldList = file.getImportList();
137 if (oldList.isReplaceEquivalent(resultList)) return null;
138 return resultList;
140 catch(IncorrectOperationException e) {
141 LOG.error(e);
142 return null;
146 @NotNull
147 private static Set<String> findSingleImports(@NotNull final PsiJavaFile file,
148 @NotNull String[] names,
149 @NotNull final Set<String> onDemandImports,
150 @NotNull Set<String> namesToImportStaticly) {
151 final GlobalSearchScope resolveScope = file.getResolveScope();
152 Set<String> namesToUseSingle = new THashSet<String>();
153 final String thisPackageName = file.getPackageName();
154 final Set<String> implicitlyImportedPackages = new THashSet<String>(Arrays.asList(file.getImplicitlyImportedPackages()));
155 final PsiManager manager = file.getManager();
156 for (String name : names) {
157 String prefix = getPackageOrClassName(name);
158 if (prefix.length() == 0) continue;
159 final boolean isImplicitlyImported = implicitlyImportedPackages.contains(prefix);
160 if (!onDemandImports.contains(prefix) && !isImplicitlyImported) continue;
161 String shortName = PsiNameHelper.getShortClassName(name);
163 String thisPackageClass = thisPackageName.length() > 0 ? thisPackageName + "." + shortName : shortName;
164 if (JavaPsiFacade.getInstance(manager.getProject()).findClass(thisPackageClass, resolveScope) != null) {
165 namesToUseSingle.add(name);
166 continue;
168 if (!isImplicitlyImported) {
169 String langPackageClass = JAVA_LANG_PACKAGE + "." + shortName; //TODO : JSP!
170 if (JavaPsiFacade.getInstance(manager.getProject()).findClass(langPackageClass, resolveScope) != null) {
171 namesToUseSingle.add(name);
172 continue;
175 for (String onDemandName : onDemandImports) {
176 if (prefix.equals(onDemandName)) continue;
177 if (namesToImportStaticly.contains(name)) {
178 PsiClass aClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(onDemandName, resolveScope);
179 if (aClass != null) {
180 PsiField field = aClass.findFieldByName(shortName, true);
181 if (field != null && field.hasModifierProperty(PsiModifier.STATIC)) {
182 namesToUseSingle.add(name);
184 else {
185 PsiClass inner = aClass.findInnerClassByName(shortName, true);
186 if (inner != null && inner.hasModifierProperty(PsiModifier.STATIC)) {
187 namesToUseSingle.add(name);
189 else {
190 PsiMethod[] methods = aClass.findMethodsByName(shortName, true);
191 for (PsiMethod method : methods) {
192 if (method.hasModifierProperty(PsiModifier.STATIC)) {
193 namesToUseSingle.add(name);
200 else {
201 PsiClass aClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(onDemandName + "." + shortName, resolveScope);
202 if (aClass != null) {
203 namesToUseSingle.add(name);
208 return namesToUseSingle;
211 @NotNull
212 private static String buildImportListText(@NotNull String[] names,
213 @NotNull final Set<String> packagesOrClassesToImportOnDemand,
214 @NotNull final Set<String> namesToUseSingle,
215 @NotNull Set<String> namesToImportStaticly) {
216 final Set<String> importedPackagesOrClasses = new THashSet<String>();
217 @NonNls final StringBuilder buffer = new StringBuilder();
218 for (String name : names) {
219 String packageOrClassName = getPackageOrClassName(name);
220 final boolean implicitlyImported = JAVA_LANG_PACKAGE.equals(packageOrClassName);
221 boolean useOnDemand = implicitlyImported || packagesOrClassesToImportOnDemand.contains(packageOrClassName);
222 if (useOnDemand && namesToUseSingle.contains(name)) {
223 useOnDemand = false;
225 if (useOnDemand && (importedPackagesOrClasses.contains(packageOrClassName) || implicitlyImported)) continue;
226 buffer.append("import ");
227 if (namesToImportStaticly.contains(name)) buffer.append("static ");
228 if (useOnDemand) {
229 importedPackagesOrClasses.add(packageOrClassName);
230 buffer.append(packageOrClassName);
231 buffer.append(".*");
233 else {
234 buffer.append(name);
236 buffer.append(";\n");
239 return buffer.toString();
243 * Adds import if it is needed.
244 * @return false when the FQ-name have to be used in code (e.g. when conflicting imports already exist)
246 public boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass){
247 final JavaPsiFacade facade = JavaPsiFacade.getInstance(file.getProject());
248 PsiElementFactory factory = facade.getElementFactory();
249 PsiResolveHelper helper = facade.getResolveHelper();
251 String className = refClass.getQualifiedName();
252 if (className == null) return true;
253 String packageName = getPackageOrClassName(className);
254 String shortName = PsiNameHelper.getShortClassName(className);
256 PsiClass conflictSingleRef = findSingleImportByShortName(file, shortName);
257 if (conflictSingleRef != null){
258 return className.equals(conflictSingleRef.getQualifiedName());
261 PsiClass curRefClass = helper.resolveReferencedClass(shortName, file);
262 if (file.getManager().areElementsEquivalent(refClass, curRefClass)) {
263 return true;
266 boolean useOnDemand = true;
267 if (packageName.length() == 0){
268 useOnDemand = false;
271 PsiElement conflictPackageRef = findImportOnDemand(file, packageName);
272 if (conflictPackageRef != null) {
273 useOnDemand = false;
276 List<PsiElement> classesToReimport = new ArrayList<PsiElement>();
278 List<PsiJavaCodeReferenceElement> importRefs = getImportsFromPackage(file, packageName);
279 if (useOnDemand){
280 if (mySettings.USE_SINGLE_CLASS_IMPORTS &&
281 importRefs.size() + 1 < mySettings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND &&
282 !mySettings.PACKAGES_TO_USE_IMPORT_ON_DEMAND.contains(packageName)) {
283 useOnDemand = false;
285 // name of class we try to import is the same as of the class defined in this file
286 if (curRefClass != null) {
287 useOnDemand = true;
289 // check conflicts
290 if (useOnDemand){
291 PsiElement[] onDemandRefs = file.getOnDemandImports(false, true);
292 if (onDemandRefs.length > 0){
293 PsiPackage aPackage = facade.findPackage(packageName);
294 if (aPackage != null){
295 PsiDirectory[] dirs = aPackage.getDirectories();
296 for (PsiDirectory dir : dirs) {
297 PsiFile[] files = dir.getFiles(); // do not iterate classes - too slow when not loaded
298 for (PsiFile aFile : files) {
299 if (aFile instanceof PsiJavaFile) {
300 String name = aFile.getVirtualFile().getNameWithoutExtension();
301 for (PsiElement ref : onDemandRefs) {
302 String refName = ref instanceof PsiClass ? ((PsiClass)ref).getQualifiedName() : ((PsiPackage)ref).getQualifiedName();
303 String conflictClassName = refName + "." + name;
304 GlobalSearchScope resolveScope = file.getResolveScope();
305 PsiClass conflictClass = facade.findClass(conflictClassName, resolveScope);
306 if (conflictClass != null && helper.isAccessible(conflictClass, file, null)) {
307 String conflictClassName2 = aPackage.getQualifiedName() + "." + name;
308 PsiClass conflictClass2 = facade.findClass(conflictClassName2, resolveScope);
309 if (conflictClass2 != null && helper.isAccessible(conflictClass2, file, null)) {
310 if (ReferencesSearch.search(conflictClass, new LocalSearchScope(file), false).findFirst() != null) {
311 classesToReimport.add(conflictClass);
324 try{
325 PsiImportList importList = file.getImportList();
326 PsiImportStatement statement;
327 if (useOnDemand) {
328 statement = factory.createImportStatementOnDemand(packageName);
329 } else {
330 statement = factory.createImportStatement(refClass);
332 importList.add(statement);
333 if (useOnDemand) {
334 for (PsiJavaCodeReferenceElement ref : importRefs) {
335 LOG.assertTrue(ref.getParent() instanceof PsiImportStatement);
336 if (!ref.isValid()) continue; // todo[dsl] Q?
337 classesToReimport.add(ref.resolve());
338 PsiImportStatement importStatement = (PsiImportStatement) ref.getParent();
339 importStatement.delete();
343 for (PsiElement aClassesToReimport : classesToReimport) {
344 PsiClass aClass = (PsiClass)aClassesToReimport;
345 if (aClass != null) {
346 addImport(file, aClass);
350 catch(IncorrectOperationException e){
351 LOG.error(e);
353 return true;
356 @NotNull
357 private static List<PsiJavaCodeReferenceElement> getImportsFromPackage(@NotNull PsiJavaFile file, @NotNull String packageName){
358 PsiClass[] refs = file.getSingleClassImports(true);
359 List<PsiJavaCodeReferenceElement> array = new ArrayList<PsiJavaCodeReferenceElement>();
360 for (PsiClass ref1 : refs) {
361 String className = ref1.getQualifiedName();
362 if (getPackageOrClassName(className).equals(packageName)) {
363 final PsiJavaCodeReferenceElement ref = file.findImportReferenceTo(ref1);
364 if (ref != null) {
365 array.add(ref);
369 return array;
372 private static PsiClass findSingleImportByShortName(@NotNull PsiJavaFile file, @NotNull String shortClassName){
373 PsiClass[] refs = file.getSingleClassImports(true);
374 for (PsiClass ref : refs) {
375 String className = ref.getQualifiedName();
376 if (className != null && PsiNameHelper.getShortClassName(className).equals(shortClassName)) {
377 return ref;
380 for (PsiClass aClass : file.getClasses()) {
381 String className = aClass.getQualifiedName();
382 if (className != null && PsiNameHelper.getShortClassName(className).equals(shortClassName)) {
383 return aClass;
386 return null;
389 private static PsiPackage findImportOnDemand(@NotNull PsiJavaFile file, @NotNull String packageName){
390 PsiElement[] refs = file.getOnDemandImports(false, true);
391 for (PsiElement ref : refs) {
392 if (ref instanceof PsiPackage && ((PsiPackage)ref).getQualifiedName().equals(packageName)) {
393 return (PsiPackage)ref;
396 return null;
399 public ASTNode getDefaultAnchor(@NotNull PsiImportList list, @NotNull PsiImportStatementBase statement){
400 PsiJavaCodeReferenceElement ref = statement.getImportReference();
401 if (ref == null) return null;
403 int entryIndex = findEntryIndex(statement);
404 PsiImportStatementBase[] allStatements = list.getAllImportStatements();
405 int[] entries = ArrayUtil.newIntArray(allStatements.length);
406 List<PsiImportStatementBase> statements = new ArrayList<PsiImportStatementBase>();
407 for(int i = 0; i < allStatements.length; i++){
408 PsiImportStatementBase statement1 = allStatements[i];
409 int entryIndex1 = findEntryIndex(statement1);
410 entries[i] = entryIndex1;
411 if (entryIndex1 == entryIndex){
412 statements.add(statement1);
416 if (statements.isEmpty()){
417 int index;
418 for(index = entries.length - 1; index >= 0; index--){
419 if (entries[index] < entryIndex) break;
421 index++;
422 return index < entries.length ? SourceTreeToPsiMap.psiElementToTree(allStatements[index]) : null;
424 else {
425 String refText = ref.getCanonicalText();
426 if (statement.isOnDemand()){
427 refText += ".";
430 PsiImportStatementBase insertBefore = null;
431 PsiImportStatementBase insertAfter = null;
432 for (PsiImportStatementBase statement1 : statements) {
433 PsiJavaCodeReferenceElement ref1 = statement1.getImportReference();
434 if (ref1 == null) {
435 continue;
437 String refTextThis = ref1.getCanonicalText();
438 if (statement1.isOnDemand()) {
439 refTextThis += ".";
442 int comp = Comparing.compare(refText, refTextThis);
443 if (comp < 0 && insertBefore == null) {
444 insertBefore = statement1;
446 if (comp > 0) {
447 insertAfter = statement1;
451 if (insertBefore != null) return insertBefore.getNode();
452 if (insertAfter != null) return insertAfter.getNode().getTreeNext();
453 return null;
457 public int getEmptyLinesBetween(@NotNull PsiImportStatementBase statement1, @NotNull PsiImportStatementBase statement2){
458 int index1 = findEntryIndex(statement1);
459 int index2 = findEntryIndex(statement2);
460 if (index1 == index2) return 0;
461 if (index1 > index2) {
462 int t = index1;
463 index1 = index2;
464 index2 = t;
466 Entry[] entries = mySettings.IMPORT_LAYOUT_TABLE.getEntries();
467 int maxSpace = 0;
468 for(int i = index1 + 1; i < index2; i++){
469 if (entries[i] instanceof EmptyLineEntry){
470 int space = 0;
472 space++;
473 } while(entries[++i] instanceof EmptyLineEntry);
474 maxSpace = Math.max(maxSpace, space);
477 return maxSpace;
480 private boolean isToUseImportOnDemand(@NotNull String packageName, int classCount, boolean isStaticImportNeeded){
481 if (!mySettings.USE_SINGLE_CLASS_IMPORTS) return true;
482 int limitCount = isStaticImportNeeded ? mySettings.NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND :
483 mySettings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND;
484 if (classCount >= limitCount) return true;
485 if (packageName.length() == 0) return false;
486 CodeStyleSettings.PackageTable table = mySettings.PACKAGES_TO_USE_IMPORT_ON_DEMAND;
487 return table != null && table.contains(packageName);
490 private int findEntryIndex(@NotNull String packageName){
491 Entry[] entries = mySettings.IMPORT_LAYOUT_TABLE.getEntries();
492 PackageEntry bestEntry = null;
493 int bestEntryIndex = -1;
494 for(int i = 0; i < entries.length; i++){
495 Entry entry = entries[i];
496 if (entry instanceof PackageEntry){
497 PackageEntry packageEntry = (PackageEntry)entry;
498 if (packageEntry.matchesPackageName(packageName)){
499 if (bestEntry == null){
500 bestEntry = packageEntry;
501 bestEntryIndex = i;
503 else{
504 String package1 = bestEntry.getPackageName();
505 String package2 = packageEntry.getPackageName();
506 if (!bestEntry.isWithSubpackages()) continue;
507 if (!packageEntry.isWithSubpackages() || package2.length() > package1.length()) {
508 bestEntry = packageEntry;
509 bestEntryIndex = i;
515 return bestEntryIndex;
518 public int findEntryIndex(@NotNull PsiImportStatementBase statement){
519 PsiJavaCodeReferenceElement ref = statement.getImportReference();
520 if (ref == null) return -1;
521 String packageName;
522 if (statement.isOnDemand()){
523 packageName = ref.getCanonicalText();
525 else{
526 String className = ref.getCanonicalText();
527 packageName = getPackageOrClassName(className);
529 return findEntryIndex(packageName);
532 @NotNull
533 private static String[] collectNamesToImport(@NotNull PsiJavaFile file, @NotNull Set<String> namesToImportStaticly){
534 Set<String> names = new THashSet<String>();
536 final JspFile jspFile = JspPsiUtil.getJspFile(file);
537 collectNamesToImport(names, file, namesToImportStaticly, jspFile);
538 if (jspFile != null) {
539 PsiFile[] files = ArrayUtil.mergeArrays(JspSpiUtil.getIncludingFiles(jspFile), JspSpiUtil.getIncludedFiles(jspFile), PsiFile.class);
540 for (PsiFile includingFile : files) {
541 final PsiFile javaRoot = includingFile.getViewProvider().getPsi(StdLanguages.JAVA);
542 if (javaRoot instanceof PsiJavaFile && file != javaRoot) {
543 collectNamesToImport(names, (PsiJavaFile)javaRoot, namesToImportStaticly, jspFile);
548 addUnresolvedImportNames(names, file, namesToImportStaticly);
550 return ArrayUtil.toStringArray(names);
553 private static void collectNamesToImport(@NotNull final Set<String> names,
554 @NotNull final PsiJavaFile file,
555 @NotNull final Set<String> namesToImportStaticly,
556 PsiFile context) {
557 String packageName = file.getPackageName();
559 final PsiElement[] roots = file.getPsiRoots();
560 for (PsiElement root : roots) {
561 addNamesToImport(names, root, packageName, namesToImportStaticly, context);
565 private static void addNamesToImport(@NotNull Set<String> names,
566 @NotNull PsiElement scope,
567 @NotNull String thisPackageName,
568 @NotNull Set<String> namesToImportStaticly,
569 PsiFile context){
570 if (scope instanceof PsiImportList) return;
572 final LinkedList<PsiElement> stack = new LinkedList<PsiElement>();
573 stack.add(scope);
574 while (!stack.isEmpty()) {
575 final PsiElement child = stack.removeFirst();
576 if (child instanceof PsiImportList) continue;
577 stack.addAll(Arrays.asList(child.getChildren()));
579 for(final PsiReference reference : child.getReferences()){
580 if (!(reference instanceof PsiJavaReference)) continue;
581 final PsiJavaReference javaReference = (PsiJavaReference)reference;
582 if (javaReference instanceof JavaClassReference){
583 if(((JavaClassReference)javaReference).getContextReference() != null) continue;
585 PsiJavaCodeReferenceElement referenceElement = null;
586 if (reference instanceof PsiJavaCodeReferenceElement) {
587 referenceElement = (PsiJavaCodeReferenceElement)child;
588 if (referenceElement.getQualifier() != null) {
589 continue;
591 if (reference instanceof PsiJavaCodeReferenceElementImpl
592 && ((PsiJavaCodeReferenceElementImpl)reference).getKind() == PsiJavaCodeReferenceElementImpl.CLASS_IN_QUALIFIED_NEW_KIND) {
593 continue;
597 final JavaResolveResult resolveResult = javaReference.advancedResolve(true);
598 PsiElement refElement = resolveResult.getElement();
599 if (refElement == null && referenceElement != null) {
600 refElement = ResolveClassUtil.resolveClass(referenceElement); // might be uncomplete code
603 PsiElement currentFileResolveScope = resolveResult.getCurrentFileResolveScope();
604 if (!(currentFileResolveScope instanceof PsiImportStatementBase)) continue;
605 if (context != null && currentFileResolveScope instanceof JspxImportStatement && context != ((JspxImportStatement)currentFileResolveScope).getDeclarationFile()) {
606 continue;
609 if (refElement != null) {
610 //Add names imported statically
611 if (referenceElement != null) {
612 if (currentFileResolveScope instanceof PsiImportStaticStatement) {
613 PsiImportStaticStatement importStaticStatement = (PsiImportStaticStatement)currentFileResolveScope;
614 String name = importStaticStatement.getImportReference().getCanonicalText();
615 if (importStaticStatement.isOnDemand()) {
616 String refName = referenceElement.getReferenceName();
617 if (refName != null) name = name + "." + refName;
619 names.add(name);
620 namesToImportStaticly.add(name);
621 continue;
625 if (refElement instanceof PsiClass) {
626 String qName = ((PsiClass)refElement).getQualifiedName();
627 if (hasPackage(qName, thisPackageName)) continue;
628 names.add(qName);
635 private static void addUnresolvedImportNames(@NotNull Set<String> set,
636 @NotNull PsiJavaFile file,
637 @NotNull Set<String> namesToImportStaticly) {
638 PsiImportStatementBase[] imports = file.getImportList().getAllImportStatements();
639 for (PsiImportStatementBase anImport : imports) {
640 PsiJavaCodeReferenceElement ref = anImport.getImportReference();
641 if (ref == null) continue;
642 JavaResolveResult[] results = ref.multiResolve(false);
643 if (results.length == 0) {
644 String text = ref.getCanonicalText();
645 if (anImport.isOnDemand()) {
646 text += ".*";
648 if (anImport instanceof PsiImportStaticStatement) {
649 namesToImportStaticly.add(text);
651 set.add(text);
656 public static boolean isImplicitlyImported(@NotNull String className, @NotNull PsiJavaFile file) {
657 String[] packageNames = file.getImplicitlyImportedPackages();
658 for (String packageName : packageNames) {
659 if (hasPackage(className, packageName)) return true;
661 return false;
664 public static boolean hasPackage(@NotNull String className, @NotNull String packageName){
665 if (!className.startsWith(packageName)) return false;
666 if (className.length() == packageName.length()) return false;
667 if (packageName.length() > 0 && className.charAt(packageName.length()) != '.') return false;
668 return className.indexOf('.', packageName.length() + 1) < 0;
671 @NotNull
672 private static String getPackageOrClassName(@NotNull String className){
673 int dotIndex = className.lastIndexOf('.');
674 return dotIndex < 0 ? "" : className.substring(0, dotIndex);