private static void autoImport(final PsiFile file, int offset, final Editor editor) { final CharSequence text = editor.getDocument().getCharsSequence(); while (offset > 0 && Character.isJavaIdentifierPart(text.charAt(offset))) offset--; if (offset <= 0) return; while (offset > 0 && Character.isWhitespace(text.charAt(offset))) offset--; if (offset <= 0 || text.charAt(offset) != '.') return; offset--; while (offset > 0 && Character.isWhitespace(text.charAt(offset))) offset--; if (offset <= 0) return; PsiJavaCodeReferenceElement element = extractReference( PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiExpression.class, false)); if (element == null) return; while (true) { final PsiJavaCodeReferenceElement qualifier = extractReference(element.getQualifier()); if (qualifier == null) break; element = qualifier; } if (!(element.getParent() instanceof PsiMethodCallExpression) && element.multiResolve(true).length == 0) { new ImportClassFix(element).doFix(editor, false, false); } }
@Override public void beforeCompletion(@NotNull final CompletionInitializationContext context) { final PsiFile file = context.getFile(); if (file instanceof PsiJavaFile) { JavaCompletionUtil.initOffsets(file, context.getOffsetMap()); autoImport(file, context.getStartOffset() - 1, context.getEditor()); if (context.getCompletionType() == CompletionType.BASIC) { if (semicolonNeeded(context.getEditor(), file, context.getStartOffset())) { context.setDummyIdentifier(CompletionInitializationContext.DUMMY_IDENTIFIER.trim() + ";"); return; } final PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset( file, context.getStartOffset(), PsiJavaCodeReferenceElement.class, false); if (ref != null && !(ref instanceof PsiReferenceExpression)) { if (ref.getParent() instanceof PsiTypeElement) { context.setDummyIdentifier( CompletionInitializationContext.DUMMY_IDENTIFIER.trim() + ";"); } if (JavaSmartCompletionContributor.AFTER_NEW.accepts(ref)) { final PsiReferenceParameterList paramList = ref.getParameterList(); if (paramList != null && paramList.getTextLength() > 0) { context .getOffsetMap() .addOffset( ConstructorInsertHandler.PARAM_LIST_START, paramList.getTextRange().getStartOffset()); context .getOffsetMap() .addOffset( ConstructorInsertHandler.PARAM_LIST_END, paramList.getTextRange().getEndOffset()); } } return; } final PsiElement element = file.findElementAt(context.getStartOffset()); if (psiElement().inside(PsiAnnotation.class).accepts(element)) { return; } context.setDummyIdentifier(CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED); } } }
public static boolean semicolonNeeded(final Editor editor, PsiFile file, final int startOffset) { final PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset( file, startOffset, PsiJavaCodeReferenceElement.class, false); if (ref != null && !(ref instanceof PsiReferenceExpression)) { if (ref.getParent() instanceof PsiTypeElement) { return true; } } HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(startOffset); if (iterator.atEnd()) return false; if (iterator.getTokenType() == JavaTokenType.IDENTIFIER) { iterator.advance(); } while (!iterator.atEnd() && ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(iterator.getTokenType())) { iterator.advance(); } if (!iterator.atEnd() && (iterator.getTokenType() == JavaTokenType.LPARENTH)) { return true; } if (!iterator.atEnd() && (iterator.getTokenType() == JavaTokenType.COLON) && null == PsiTreeUtil.findElementOfClassAtOffset( file, startOffset, PsiConditionalExpression.class, false)) { return true; } while (!iterator.atEnd() && ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(iterator.getTokenType())) { iterator.advance(); } if (iterator.atEnd() || iterator.getTokenType() != JavaTokenType.IDENTIFIER) return false; iterator.advance(); while (!iterator.atEnd() && ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(iterator.getTokenType())) { iterator.advance(); } if (iterator.atEnd()) return false; return iterator.getTokenType() == JavaTokenType.EQ || iterator.getTokenType() == JavaTokenType.LPARENTH; }
private static void autoImportReference( @NotNull PsiFile file, @NotNull Editor editor, @Nullable PsiJavaCodeReferenceElement element) { if (element == null) return; while (true) { final PsiJavaCodeReferenceElement qualifier = extractReference(element.getQualifier()); if (qualifier == null) break; element = qualifier; } if (!(element.getParent() instanceof PsiMethodCallExpression) && element.multiResolve(true).length == 0) { new ImportClassFix(element).doFix(editor, false, false); PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument()); } }
/** * Adds import if it is needed. * * @return false when the FQ-name have to be used in code (e.g. when conflicting imports already * exist) */ public boolean addImport(@NotNull PsiJavaFile file, @NotNull PsiClass refClass) { final JavaPsiFacade facade = JavaPsiFacade.getInstance(file.getProject()); PsiElementFactory factory = facade.getElementFactory(); PsiResolveHelper helper = facade.getResolveHelper(); String className = refClass.getQualifiedName(); if (className == null) return true; String packageName = getPackageOrClassName(className); String shortName = PsiNameHelper.getShortClassName(className); PsiClass conflictSingleRef = findSingleImportByShortName(file, shortName); if (conflictSingleRef != null) { return className.equals(conflictSingleRef.getQualifiedName()); } PsiClass curRefClass = helper.resolveReferencedClass(shortName, file); if (file.getManager().areElementsEquivalent(refClass, curRefClass)) { return true; } boolean useOnDemand = true; if (packageName.length() == 0) { useOnDemand = false; } PsiElement conflictPackageRef = findImportOnDemand(file, packageName); if (conflictPackageRef != null) { useOnDemand = false; } List<PsiElement> classesToReimport = new ArrayList<PsiElement>(); List<PsiJavaCodeReferenceElement> importRefs = getImportsFromPackage(file, packageName); if (useOnDemand) { if (mySettings.USE_SINGLE_CLASS_IMPORTS && importRefs.size() + 1 < mySettings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND && !mySettings.PACKAGES_TO_USE_IMPORT_ON_DEMAND.contains(packageName)) { useOnDemand = false; } // name of class we try to import is the same as of the class defined in this file if (curRefClass != null) { useOnDemand = true; } // check conflicts if (useOnDemand) { PsiElement[] onDemandRefs = file.getOnDemandImports(false, true); if (onDemandRefs.length > 0) { PsiPackage aPackage = facade.findPackage(packageName); if (aPackage != null) { PsiDirectory[] dirs = aPackage.getDirectories(); for (PsiDirectory dir : dirs) { PsiFile[] files = dir.getFiles(); // do not iterate classes - too slow when not loaded for (PsiFile aFile : files) { if (aFile instanceof PsiJavaFile) { String name = aFile.getVirtualFile().getNameWithoutExtension(); for (PsiElement ref : onDemandRefs) { String refName = ref instanceof PsiClass ? ((PsiClass) ref).getQualifiedName() : ((PsiPackage) ref).getQualifiedName(); String conflictClassName = refName + "." + name; GlobalSearchScope resolveScope = file.getResolveScope(); PsiClass conflictClass = facade.findClass(conflictClassName, resolveScope); if (conflictClass != null && helper.isAccessible(conflictClass, file, null)) { String conflictClassName2 = aPackage.getQualifiedName() + "." + name; PsiClass conflictClass2 = facade.findClass(conflictClassName2, resolveScope); if (conflictClass2 != null && helper.isAccessible(conflictClass2, file, null)) { if (ReferencesSearch.search( conflictClass, new LocalSearchScope(file), false) .findFirst() != null) { classesToReimport.add(conflictClass); } } } } } } } } } } } try { PsiImportList importList = file.getImportList(); PsiImportStatement statement; if (useOnDemand) { statement = factory.createImportStatementOnDemand(packageName); } else { statement = factory.createImportStatement(refClass); } importList.add(statement); if (useOnDemand) { for (PsiJavaCodeReferenceElement ref : importRefs) { LOG.assertTrue(ref.getParent() instanceof PsiImportStatement); if (!ref.isValid()) continue; // todo[dsl] Q? classesToReimport.add(ref.resolve()); PsiImportStatement importStatement = (PsiImportStatement) ref.getParent(); importStatement.delete(); } } for (PsiElement aClassesToReimport : classesToReimport) { PsiClass aClass = (PsiClass) aClassesToReimport; if (aClass != null) { addImport(file, aClass); } } } catch (IncorrectOperationException e) { LOG.error(e); } return true; }