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
;
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!
67 ArrayList
<String
> namesList
= new ArrayList
<String
>();
68 ImportLayoutTable table
= mySettings
.IMPORT_LAYOUT_TABLE
;
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
]);
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);
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
);
123 classToCountMap
.forEachEntry(new MyVisitorProcedure(false));
124 packageToCountMap
.forEachEntry(new MyVisitorProcedure(true));
126 Set
<String
> classesToUseSingle
= findSingleImports(file
, names
, classesOrPackagesToImportOnDemand
, namesToImportStaticly
);
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;
140 catch(IncorrectOperationException e
) {
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
);
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
);
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
);
185 PsiClass inner
= aClass
.findInnerClassByName(shortName
, true);
186 if (inner
!= null && inner
.hasModifierProperty(PsiModifier
.STATIC
)) {
187 namesToUseSingle
.add(name
);
190 PsiMethod
[] methods
= aClass
.findMethodsByName(shortName
, true);
191 for (PsiMethod method
: methods
) {
192 if (method
.hasModifierProperty(PsiModifier
.STATIC
)) {
193 namesToUseSingle
.add(name
);
201 PsiClass aClass
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass(onDemandName
+ "." + shortName
, resolveScope
);
202 if (aClass
!= null) {
203 namesToUseSingle
.add(name
);
208 return namesToUseSingle
;
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
)) {
225 if (useOnDemand
&& (importedPackagesOrClasses
.contains(packageOrClassName
) || implicitlyImported
)) continue;
226 buffer
.append("import ");
227 if (namesToImportStaticly
.contains(name
)) buffer
.append("static ");
229 importedPackagesOrClasses
.add(packageOrClassName
);
230 buffer
.append(packageOrClassName
);
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
)) {
266 boolean useOnDemand
= true;
267 if (packageName
.length() == 0){
271 PsiElement conflictPackageRef
= findImportOnDemand(file
, packageName
);
272 if (conflictPackageRef
!= null) {
276 List
<PsiElement
> classesToReimport
= new ArrayList
<PsiElement
>();
278 List
<PsiJavaCodeReferenceElement
> importRefs
= getImportsFromPackage(file
, packageName
);
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
)) {
285 // name of class we try to import is the same as of the class defined in this file
286 if (curRefClass
!= null) {
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
);
325 PsiImportList importList
= file
.getImportList();
326 PsiImportStatement statement
;
328 statement
= factory
.createImportStatementOnDemand(packageName
);
330 statement
= factory
.createImportStatement(refClass
);
332 importList
.add(statement
);
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
){
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
);
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
)) {
380 for (PsiClass aClass
: file
.getClasses()) {
381 String className
= aClass
.getQualifiedName();
382 if (className
!= null && PsiNameHelper
.getShortClassName(className
).equals(shortClassName
)) {
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
;
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()){
418 for(index
= entries
.length
- 1; index
>= 0; index
--){
419 if (entries
[index
] < entryIndex
) break;
422 return index
< entries
.length ? SourceTreeToPsiMap
.psiElementToTree(allStatements
[index
]) : null;
425 String refText
= ref
.getCanonicalText();
426 if (statement
.isOnDemand()){
430 PsiImportStatementBase insertBefore
= null;
431 PsiImportStatementBase insertAfter
= null;
432 for (PsiImportStatementBase statement1
: statements
) {
433 PsiJavaCodeReferenceElement ref1
= statement1
.getImportReference();
437 String refTextThis
= ref1
.getCanonicalText();
438 if (statement1
.isOnDemand()) {
442 int comp
= Comparing
.compare(refText
, refTextThis
);
443 if (comp
< 0 && insertBefore
== null) {
444 insertBefore
= statement1
;
447 insertAfter
= statement1
;
451 if (insertBefore
!= null) return insertBefore
.getNode();
452 if (insertAfter
!= null) return insertAfter
.getNode().getTreeNext();
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
) {
466 Entry
[] entries
= mySettings
.IMPORT_LAYOUT_TABLE
.getEntries();
468 for(int i
= index1
+ 1; i
< index2
; i
++){
469 if (entries
[i
] instanceof EmptyLineEntry
){
473 } while(entries
[++i
] instanceof EmptyLineEntry
);
474 maxSpace
= Math
.max(maxSpace
, space
);
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
;
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
;
515 return bestEntryIndex
;
518 public int findEntryIndex(@NotNull PsiImportStatementBase statement
){
519 PsiJavaCodeReferenceElement ref
= statement
.getImportReference();
520 if (ref
== null) return -1;
522 if (statement
.isOnDemand()){
523 packageName
= ref
.getCanonicalText();
526 String className
= ref
.getCanonicalText();
527 packageName
= getPackageOrClassName(className
);
529 return findEntryIndex(packageName
);
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
,
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
,
570 if (scope
instanceof PsiImportList
) return;
572 final LinkedList
<PsiElement
> stack
= new LinkedList
<PsiElement
>();
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) {
591 if (reference
instanceof PsiJavaCodeReferenceElementImpl
592 && ((PsiJavaCodeReferenceElementImpl
)reference
).getKind() == PsiJavaCodeReferenceElementImpl
.CLASS_IN_QUALIFIED_NEW_KIND
) {
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()) {
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
;
620 namesToImportStaticly
.add(name
);
625 if (refElement
instanceof PsiClass
) {
626 String qName
= ((PsiClass
)refElement
).getQualifiedName();
627 if (hasPackage(qName
, thisPackageName
)) continue;
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()) {
648 if (anImport
instanceof PsiImportStaticStatement
) {
649 namesToImportStaticly
.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;
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;
672 private static String
getPackageOrClassName(@NotNull String className
){
673 int dotIndex
= className
.lastIndexOf('.');
674 return dotIndex
< 0 ?
"" : className
.substring(0, dotIndex
);