diff --git a/community-main.iml b/community-main.iml index e984246e74c7..e3109b8263bf 100644 --- a/community-main.iml +++ b/community-main.iml @@ -77,6 +77,15 @@ + + + + + + + + + diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index dd503c74277e..5cbc5fea985e 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -1038,12 +1038,12 @@ public class CompileDriver { generatedTypes.addAll(compilerManager.getRegisteredOutputTypes(compiler)); } - if (_context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - throw new ExitException(ExitStatus.ERRORS); - } - didSomething |= compiledSomething; compiledSomethingForThisChunk |= didSomething; + + if (_context.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + break; // break the loop over compilers + } } final boolean hasUnprocessedTraverseRoots = context.getDependencyCache().hasUnprocessedTraverseRoots(); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java index 5d12ced33651..efff8ab5787a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java @@ -351,7 +351,7 @@ public class DebugProcessEvents extends DebugProcessImpl { //noinspection HardCodedStringLiteral RequestHint hint = (RequestHint)event.request().getProperty("hint"); - deleteStepRequests(); + deleteStepRequests(event.thread()); boolean shouldResume = false; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index 0e907ad96f1f..c88999862fdc 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -353,12 +353,13 @@ public abstract class DebugProcessImpl implements DebugProcess { return; } try { + final ThreadReference stepThreadReference = stepThread.getThreadReference(); if (LOG.isDebugEnabled()) { - LOG.debug("DO_STEP: creating step request for " + stepThread.getThreadReference()); + LOG.debug("DO_STEP: creating step request for " + stepThreadReference); } - deleteStepRequests(); + deleteStepRequests(stepThreadReference); EventRequestManager requestManager = getVirtualMachineProxy().eventRequestManager(); - StepRequest stepRequest = requestManager.createStepRequest(stepThread.getThreadReference(), StepRequest.STEP_LINE, depth); + StepRequest stepRequest = requestManager.createStepRequest(stepThreadReference, StepRequest.STEP_LINE, depth); DebuggerSettings settings = DebuggerSettings.getInstance(); if (!(hint != null && hint.isIgnoreFilters()) /*&& depth == StepRequest.STEP_INTO*/) { final List activeFilters = new ArrayList(); @@ -404,7 +405,7 @@ public abstract class DebugProcessImpl implements DebugProcess { } } - void deleteStepRequests() { + void deleteStepRequests(@Nullable final ThreadReference stepThread) { EventRequestManager requestManager = getVirtualMachineProxy().eventRequestManager(); List stepRequests = requestManager.stepRequests(); if (stepRequests.size() > 0) { @@ -412,7 +413,7 @@ public abstract class DebugProcessImpl implements DebugProcess { for (final StepRequest request : stepRequests) { ThreadReference threadReference = request.thread(); // [jeka] on attempt to delete a request assigned to a thread with unknown status, a JDWP error occures - if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN) { + if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN && (stepThread == null || stepThread.equals(threadReference))) { toDelete.add(request); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java index 07bed88ea199..110d70270f5d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java @@ -298,7 +298,8 @@ public class SuspendManagerImpl implements SuspendManager { } myDebugProcess.logThreads(); myDebugProcess.cancelRunToCursorBreakpoint(); - myDebugProcess.deleteStepRequests(); + final ThreadReferenceProxyImpl thread = suspendContext.getThread(); + myDebugProcess.deleteStepRequests(thread != null? thread.getThreadReference() : null); notifyPaused(suspendContext); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java index 472402354c00..9ea0bfe2ba0c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java @@ -127,59 +127,55 @@ public class LineBreakpoint extends BreakpointWithHighlighter { if (!isInScopeOf(debugProcess, classType.name())) { return; } - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - try { - List locs = debugProcess.getPositionManager().locationsOfLine(classType, getSourcePosition()); - if (locs.size() > 0) { - for (final Location location : locs) { - if (LOG.isDebugEnabled()) { - LOG.debug("Found location for reference type " + classType.name() + " at line " + getLineIndex() + "; isObsolete: " + (debugProcess.getVirtualMachineProxy().versionHigher("1.4") && location.method().isObsolete())); - } - BreakpointRequest request = debugProcess.getRequestsManager().createBreakpointRequest(LineBreakpoint.this, location); - debugProcess.getRequestsManager().enableRequest(request); - if (LOG.isDebugEnabled()) { - LOG.debug("Created breakpoint request for reference type " + classType.name() + " at line " + getLineIndex()); - } - } - } - else { - // there's no executable code in this class - debugProcess.getRequestsManager().setInvalid(LineBreakpoint.this, DebuggerBundle.message( - "error.invalid.breakpoint.no.executable.code", (getLineIndex() + 1), classType.name()) - ); - if (LOG.isDebugEnabled()) { - LOG.debug("No locations of type " + classType.name() + " found at line " + getLineIndex()); - } - } - } - catch (ClassNotPreparedException ex) { + try { + List locs = debugProcess.getPositionManager().locationsOfLine(classType, getSourcePosition()); + if (locs.size() > 0) { + for (final Location location : locs) { if (LOG.isDebugEnabled()) { - LOG.debug("ClassNotPreparedException: " + ex.getMessage()); + LOG.debug("Found location for reference type " + classType.name() + " at line " + getLineIndex() + "; isObsolete: " + (debugProcess.getVirtualMachineProxy().versionHigher("1.4") && location.method().isObsolete())); } - // there's a chance to add a breakpoint when the class is prepared - } - catch (ObjectCollectedException ex) { + BreakpointRequest request = debugProcess.getRequestsManager().createBreakpointRequest(LineBreakpoint.this, location); + debugProcess.getRequestsManager().enableRequest(request); if (LOG.isDebugEnabled()) { - LOG.debug("ObjectCollectedException: " + ex.getMessage()); + LOG.debug("Created breakpoint request for reference type " + classType.name() + " at line " + getLineIndex()); } - // there's a chance to add a breakpoint when the class is prepared } - catch (InvalidLineNumberException ex) { - if (LOG.isDebugEnabled()) { - LOG.debug("InvalidLineNumberException: " + ex.getMessage()); - } - debugProcess.getRequestsManager().setInvalid(LineBreakpoint.this, DebuggerBundle.message("error.invalid.breakpoint.bad.line.number")); - } - catch (InternalException ex) { - LOG.info(ex); - } - catch(Exception ex) { - LOG.info(ex); - } - updateUI(); } - }); + else { + // there's no executable code in this class + debugProcess.getRequestsManager().setInvalid(LineBreakpoint.this, DebuggerBundle.message( + "error.invalid.breakpoint.no.executable.code", (getLineIndex() + 1), classType.name()) + ); + if (LOG.isDebugEnabled()) { + LOG.debug("No locations of type " + classType.name() + " found at line " + getLineIndex()); + } + } + } + catch (ClassNotPreparedException ex) { + if (LOG.isDebugEnabled()) { + LOG.debug("ClassNotPreparedException: " + ex.getMessage()); + } + // there's a chance to add a breakpoint when the class is prepared + } + catch (ObjectCollectedException ex) { + if (LOG.isDebugEnabled()) { + LOG.debug("ObjectCollectedException: " + ex.getMessage()); + } + // there's a chance to add a breakpoint when the class is prepared + } + catch (InvalidLineNumberException ex) { + if (LOG.isDebugEnabled()) { + LOG.debug("InvalidLineNumberException: " + ex.getMessage()); + } + debugProcess.getRequestsManager().setInvalid(LineBreakpoint.this, DebuggerBundle.message("error.invalid.breakpoint.bad.line.number")); + } + catch (InternalException ex) { + LOG.info(ex); + } + catch(Exception ex) { + LOG.info(ex); + } + updateUI(); } private boolean isInScopeOf(DebugProcessImpl debugProcess, String className) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java index 91d283bba58d..1f7c36f5a010 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java @@ -132,6 +132,7 @@ public class AllClassesGetter { start--; } context.getDocument().replaceString(start + 1, context.getTailOffset(), qName); + LOG.assertTrue(context.getTailOffset() >= 0); } } }; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java index 1ad49a9ddbdf..1e4e1a6bb2fb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.AutoPopupController; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -94,7 +95,18 @@ class JavaClassNameInsertHandler implements InsertHandler= 0); + String docText = context.getDocument().getText(); DefaultInsertHandler.addImportForItem(context.getFile(), context.getStartOffset(), item); + if (context.getTailOffset() < 0) { + if (ApplicationManagerEx.getApplicationEx().isInternal()) { + LOG.error("Tail offset degraded: " + context.getStartOffset() + "; " + docText); + } else { + LOG.error("Tail offset degraded after insertion"); + } + } + if (annotation) { // Check if someone inserts annotation class that require @ diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 89a09e685c17..c1955ee5df1d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -923,14 +923,21 @@ public class JavaCompletionUtil { public static void insertParentheses(final InsertionContext context, final LookupElement item, boolean overloadsMatter, boolean hasParams) { final Editor editor = context.getEditor(); - final TailType tailType = getTailType(item, context); + final char completionChar = context.getCompletionChar(); final PsiFile file = context.getFile(); + final TailType tailType = completionChar == '(' ? TailType.NONE : LookupItem.handleCompletionChar(context.getEditor(), item, completionChar); + final boolean hasTail = tailType != TailType.NONE && tailType != TailType.UNKNOWN; + final boolean smart = completionChar == Lookup.COMPLETE_STATEMENT_SELECT_CHAR; + + final boolean addCompletionChar = context.shouldAddCompletionChar(); context.setAddCompletionChar(false); - final boolean needLeftParenth = isToInsertParenth(file.findElementAt(context.getStartOffset())); - final boolean needRightParenth = tailType != TailType.SMART_COMPLETION && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET; + final boolean needRightParenth = !smart && (CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET || hasTail); + if (hasTail) { + hasParams = false; + } if (needLeftParenth) { final CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(context.getProject()); @@ -947,42 +954,20 @@ public class JavaCompletionUtil { AutoPopupController.getInstance(file.getProject()).autoPopupParameterInfo(editor, overloadsMatter ? null : (PsiElement)item.getObject()); } - if (tailType == TailType.SEMICOLON) { - if (!needRightParenth) { - return; - } - - PsiDocumentManager.getInstance(file.getProject()).commitAllDocuments(); - if (psiElement().beforeLeaf(psiElement().withText(".")).accepts(file.findElementAt(context.getTailOffset() - 1))) { - return; + if (smart || needLeftParenth && needRightParenth && addCompletionChar) { + TailType toInsert = tailType; + LookupItem lookupItem = item.as(LookupItem.class); + if (lookupItem == null || lookupItem.getAttribute(LookupItem.TAIL_TYPE_ATTR) != TailType.UNKNOWN) { + if (!hasTail && item.getObject() instanceof PsiMethod && ((PsiMethod)item.getObject()).getReturnType() == PsiType.VOID) { + PsiDocumentManager.getInstance(file.getProject()).commitAllDocuments(); + if (psiElement().beforeLeaf(psiElement().withText(".")).accepts(file.findElementAt(context.getTailOffset() - 1))) { + return; + } + toInsert = TailType.SEMICOLON; + } } + toInsert.processTail(editor, context.getTailOffset()); } - - if (tailType == TailType.SMART_COMPLETION || needLeftParenth && needRightParenth) { - tailType.processTail(editor, context.getTailOffset()); - } - } - - @NotNull - public static TailType getTailType(final LookupElement item, InsertionContext context) { - final char completionChar = context.getCompletionChar(); - if (completionChar == '!') return item instanceof LookupItem ? ((LookupItem)item).getTailType() : TailType.NONE; - if (completionChar == '(') { - final Object o = item.getObject(); - if (o instanceof PsiMethod) { - final PsiMethod psiMethod = (PsiMethod)o; - return psiMethod.getParameterList().getParameters().length > 0 || psiMethod.getReturnType() != PsiType.VOID - ? TailType.NONE : TailType.SEMICOLON; - } else if (o instanceof PsiClass) { // it may be a constructor - return TailType.NONE; - } - } - if (completionChar == Lookup.COMPLETE_STATEMENT_SELECT_CHAR) return TailType.SMART_COMPLETION; - if (!context.shouldAddCompletionChar()) { - return TailType.NONE; - } - - return LookupItem.handleCompletionChar(context.getEditor(), item, completionChar); } public static boolean isToInsertParenth(PsiElement place){ diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java index a6a754150700..00a0ac458506 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java @@ -17,7 +17,6 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; -import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.completion.util.MethodParenthesesHandler; import com.intellij.codeInsight.lookup.*; import com.intellij.codeInsight.lookup.impl.JavaElementLookupRenderer; @@ -57,8 +56,6 @@ public class JavaMethodCallElement extends LookupItem implements Type LOG.error(method.getName()); } myCanImportStatic = canImportStatic; - PsiType type = method.getReturnType(); - setTailType(PsiType.VOID.equals(type) ? TailType.SEMICOLON : TailType.NONE); } public PsiType getType() { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RemoveSuppressWarningAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RemoveSuppressWarningAction.java index 972cc03e1441..dec89978d01f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RemoveSuppressWarningAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RemoveSuppressWarningAction.java @@ -138,7 +138,7 @@ public class RemoveSuppressWarningAction implements LocalQuickFix { } else if (newText != null) { newText = "@" + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + newText; - PsiDocTag newTag = JavaPsiFacade.getInstance(tag.getProject()).getElementFactory().createDocTagFromText(newText, tag); + PsiDocTag newTag = JavaPsiFacade.getInstance(tag.getProject()).getElementFactory().createDocTagFromText(newText); tag.replace(newTag); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressAllForClassFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressAllForClassFix.java index 421a8161fd30..e39e54fbf800 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressAllForClassFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressAllForClassFix.java @@ -84,7 +84,7 @@ public class SuppressAllForClassFix extends SuppressFix { PsiDocTag noInspectionTag = docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME); if (noInspectionTag != null) { String tagText = "@" + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + SuppressionUtil.ALL; - noInspectionTag.replace(JavaPsiFacade.getInstance(project).getElementFactory().createDocTagFromText(tagText, null)); + noInspectionTag.replace(JavaPsiFacade.getInstance(project).getElementFactory().createDocTagFromText(tagText)); DaemonCodeAnalyzer.getInstance(project).restart(); return; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java index 99db61ace268..b3fd3fbe2676 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java @@ -109,7 +109,7 @@ public class SuppressFix extends SuppressIntentionAction { PsiManager manager = PsiManager.getInstance(project); if (docComment == null) { String commentText = "/** @" + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + getID(container) + "*/"; - docComment = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocCommentFromText(commentText, null); + docComment = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocCommentFromText(commentText); PsiElement firstChild = container.getFirstChild(); container.addBefore(docComment, firstChild); } @@ -122,11 +122,11 @@ public class SuppressFix extends SuppressIntentionAction { " " + (valueElement != null ? valueElement.getText() + "," : "") + getID(container); - noInspectionTag.replace(JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocTagFromText(tagText, null)); + noInspectionTag.replace(JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocTagFromText(tagText)); } else { String tagText = "@" + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + getID(container); - docComment.add(JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocTagFromText(tagText, null)); + docComment.add(JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocTagFromText(tagText)); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java index 5b5355f5f048..56b34711ed8b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java @@ -176,7 +176,7 @@ public class VariableAccessFromInnerClassFix implements IntentionAction { variableDeclarationStatement = factory.createVariableDeclarationStatement(variable.getName(), newType, init); } else { - PsiExpression init = factory.createExpressionFromText(" { " + initializer.getText() + " }", variable); + PsiExpression init = factory.createExpressionFromText("{ " + initializer.getText() + " }", variable); variableDeclarationStatement = factory.createVariableDeclarationStatement(variable.getName(), newType, init); } PsiVariable newVariable = (PsiVariable)variableDeclarationStatement.getDeclaredElements()[0]; diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConvertToBasicLatinAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConvertToBasicLatinAction.java index 98a5bcf697aa..e4b0467119e9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConvertToBasicLatinAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConvertToBasicLatinAction.java @@ -177,7 +177,7 @@ public class ConvertToBasicLatinAction extends PsiElementBaseIntentionAction { } public PsiElement createReplacement(final PsiElement element, final String newText) { - return JavaPsiFacade.getElementFactory(element.getProject()).createDocCommentFromText(newText, element.getParent()); + return JavaPsiFacade.getElementFactory(element.getProject()).createDocCommentFromText(newText); } private static void loadEntities(final Project project) { diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java index 521756db08eb..da5558d9c490 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java @@ -145,8 +145,18 @@ public class SplitDeclarationAction extends PsiElementBaseIntentionAction { } } - block.getParent().addBefore(varDeclStatement, block); + final PsiElement parent = block.getParent(); decl.replace(statement); + if (!(parent instanceof PsiCodeBlock)) { + final PsiBlockStatement blockStatement = + (PsiBlockStatement)JavaPsiFacade.getElementFactory(project).createStatementFromText("{}", null); + final PsiCodeBlock codeBlock = blockStatement.getCodeBlock(); + codeBlock.add(varDeclStatement); + codeBlock.add(block); + block.replace(blockStatement); + } else { + parent.addBefore(varDeclStatement, block); + } } else { block.addAfter(statement, decl); } diff --git a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java index 6f56bc39b7f0..5d3ff59a8e97 100644 --- a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -1343,9 +1343,8 @@ public class JavaDocInfoGenerator { } else { try { - final PsiDocTag tag = JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createDocCommentFromText("/** @exception " + paramName + " */", - method.getContainingFile()).getTags()[0]; - + final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); + final PsiDocTag tag = elementFactory.createDocTagFromText("@exception " + paramName); collectedTags.addLast(new Pair>(tag, ourEmptyProvider)); } catch (IncorrectOperationException e) { diff --git a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspection.java index 73c1821c0a38..4eedb6c34abe 100644 --- a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspection.java @@ -323,7 +323,7 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool { if (owner != null) { if (!CodeInsightUtil.preparePsiElementsForWrite(owner)) return; final PsiDocComment docComment = owner.getDocComment(); - final PsiDocTag tag = factory.createDocTagFromText("@" + myTag+" "+myValue, docComment); + final PsiDocTag tag = factory.createDocTagFromText("@" + myTag + " " + myValue); if (docComment != null) { PsiElement addedTag; final PsiElement anchor = getAnchor(); diff --git a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index d1d91be0ee21..2c01a1babfe2 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -146,7 +146,7 @@ public class DeclarationParser { } @Nullable - private static PsiBuilder.Marker parseEnumConstant(final PsiBuilder builder) { + public static PsiBuilder.Marker parseEnumConstant(final PsiBuilder builder) { final PsiBuilder.Marker constant = builder.mark(); parseModifierList(builder); diff --git a/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java index 99982aed1d3d..9313500b6149 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java @@ -184,13 +184,18 @@ public class JavaParserUtil { return builder; } + @Nullable public static ASTNode parseFragment(final ASTNode chameleon, final ParserWrapper wrapper) { + return parseFragment(chameleon, wrapper, true, LanguageLevel.HIGHEST); + } + + @Nullable + public static ASTNode parseFragment(final ASTNode chameleon, final ParserWrapper wrapper, final boolean eatAll, final LanguageLevel level) { final PsiElement psi = (chameleon.getTreeParent() != null ? chameleon.getTreeParent().getPsi() : chameleon.getPsi()); assert psi != null : chameleon; final Project project = psi.getProject(); final PsiBuilderFactory factory = PsiBuilderFactory.getInstance(); - final LanguageLevel level = LanguageLevel.HIGHEST; final Lexer lexer = JavaParserDefinition.createLexer(level); final PsiBuilder builder = factory.createBuilder(project, chameleon, lexer, chameleon.getElementType().getLanguage(), chameleon.getChars()); setLanguageLevel(builder, level); @@ -198,6 +203,7 @@ public class JavaParserUtil { final PsiBuilder.Marker root = builder.mark(); wrapper.parse(builder); if (!builder.eof()) { + if (!eatAll) throw new AssertionError("Unexpected tokens"); final PsiBuilder.Marker extras = builder.mark(); while (!builder.eof()) builder.advanceLexer(); extras.error(JavaErrorMessages.message("unexpected.tokens")); @@ -389,4 +395,4 @@ public class JavaParserUtil { myDelegate.putUserDataUnprotected(key, value); } } -} +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java index e6cfac8b80a2..1d25b4b7841f 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java @@ -311,7 +311,7 @@ public class ReferenceParser { } @Nullable - private static PsiBuilder.Marker parseTypeParameter(final PsiBuilder builder) { + public static PsiBuilder.Marker parseTypeParameter(final PsiBuilder builder) { final PsiBuilder.Marker param = builder.mark(); DeclarationParser.parseAnnotations(builder); diff --git a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java index 561e249289cb..42c861dc6cfa 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java @@ -165,7 +165,7 @@ public class StatementParser { } @Nullable - private static PsiBuilder.Marker parseStatement(final PsiBuilder builder) { + public static PsiBuilder.Marker parseStatement(final PsiBuilder builder) { final IElementType tokenType = builder.getTokenType(); // todo: custom parsers (?) @@ -637,7 +637,8 @@ public class StatementParser { return statement; } - private static boolean parseCatchBlock(final PsiBuilder builder) { + public static boolean parseCatchBlock(final PsiBuilder builder) { + assert builder.getTokenType() == JavaTokenType.CATCH_KEYWORD : builder.getTokenType(); final PsiBuilder.Marker section = builder.mark(); builder.advanceLexer(); diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java b/java/java-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java index 4a4c8a7620ba..e048f84772b8 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java @@ -17,7 +17,6 @@ package com.intellij.psi.impl; import com.intellij.lang.*; import com.intellij.lexer.Lexer; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -27,12 +26,15 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.impl.light.*; import com.intellij.psi.impl.source.*; import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; -import com.intellij.psi.impl.source.tree.*; +import com.intellij.psi.impl.source.tree.FileElement; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -41,30 +43,14 @@ import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.Map; +import static com.intellij.openapi.util.text.StringUtil.join; + public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements PsiElementFactory { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiElementFactoryImpl"); + private PsiClass myArrayClass; + private PsiClass myArrayClass15; + private PsiJavaFile myDummyJavaFile; - private PsiClass ARRAY_CLASS; - private PsiClass ARRAY_CLASS15; - - static { - initPrimitiveTypes(); - } - - private static void initPrimitiveTypes() { - ourPrimitiveTypesMap.put(PsiType.BYTE.getCanonicalText(), (PsiPrimitiveType)PsiType.BYTE); - ourPrimitiveTypesMap.put(PsiType.CHAR.getCanonicalText(), (PsiPrimitiveType)PsiType.CHAR); - ourPrimitiveTypesMap.put(PsiType.DOUBLE.getCanonicalText(), (PsiPrimitiveType)PsiType.DOUBLE); - ourPrimitiveTypesMap.put(PsiType.FLOAT.getCanonicalText(), (PsiPrimitiveType)PsiType.FLOAT); - ourPrimitiveTypesMap.put(PsiType.INT.getCanonicalText(), (PsiPrimitiveType)PsiType.INT); - ourPrimitiveTypesMap.put(PsiType.LONG.getCanonicalText(), (PsiPrimitiveType)PsiType.LONG); - ourPrimitiveTypesMap.put(PsiType.SHORT.getCanonicalText(), (PsiPrimitiveType)PsiType.SHORT); - ourPrimitiveTypesMap.put(PsiType.BOOLEAN.getCanonicalText(), (PsiPrimitiveType)PsiType.BOOLEAN); - ourPrimitiveTypesMap.put(PsiType.VOID.getCanonicalText(), (PsiPrimitiveType)PsiType.VOID); - ourPrimitiveTypesMap.put(PsiType.NULL.getCanonicalText(), (PsiPrimitiveType)PsiType.NULL); - } - - public PsiElementFactoryImpl(PsiManagerEx manager) { + public PsiElementFactoryImpl(final PsiManagerEx manager) { super(manager); } @@ -77,32 +63,29 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiClass getArrayClass(@NotNull LanguageLevel languageLevel) { - try { - if (languageLevel.compareTo(LanguageLevel.JDK_1_5) < 0) { - if (ARRAY_CLASS == null) { - ARRAY_CLASS = createClassFromText("public class __Array__{\n public final int length; \n public Object clone(){}\n}", null).getInnerClasses()[0]; - } - return ARRAY_CLASS; - } - else { - if (ARRAY_CLASS15 == null) { - ARRAY_CLASS15 = createClassFromText("public class __Array__{\n public final int length; \n public T[] clone(){}\n}", null).getInnerClasses()[0]; - } - return ARRAY_CLASS15; + public PsiClass getArrayClass(@NotNull final LanguageLevel languageLevel) { + if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) { + if (myArrayClass == null) { + final String body = "public class __Array__{\n public final int length;\n public Object clone() {}\n}"; + myArrayClass = createClassFromText(body, null).getInnerClasses()[0]; } + return myArrayClass; } - catch (IncorrectOperationException e) { - LOG.error(e); - return null; + else { + if (myArrayClass15 == null) { + final String body = "public class __Array__{\n public final int length;\n public T[] clone() {}\n}"; + myArrayClass15 = createClassFromText(body, null).getInnerClasses()[0]; + } + return myArrayClass15; } } @NotNull - public PsiClassType getArrayClassType(@NotNull PsiType componentType, @NotNull final LanguageLevel languageLevel) { - PsiClass arrayClass = getArrayClass(languageLevel); + public PsiClassType getArrayClassType(@NotNull final PsiType componentType, @NotNull final LanguageLevel languageLevel) { + final PsiClass arrayClass = getArrayClass(languageLevel); + final PsiTypeParameter[] typeParameters = arrayClass.getTypeParameters(); + PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; - PsiTypeParameter[] typeParameters = arrayClass.getTypeParameters(); if (typeParameters.length == 1) { substitutor = substitutor.put(typeParameters[0], componentType); } @@ -111,305 +94,227 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiClassType createType(@NotNull PsiClass resolve, @NotNull PsiSubstitutor substitutor) { + public PsiClassType createType(@NotNull final PsiClass resolve, @NotNull final PsiSubstitutor substitutor) { return new PsiImmediateClassType(resolve, substitutor); } @NotNull - public PsiClassType createType(@NotNull PsiClass resolve, @NotNull PsiSubstitutor substitutor, @NotNull LanguageLevel languageLevel) { + public PsiClassType createType(@NotNull final PsiClass resolve, + @NotNull final PsiSubstitutor substitutor, + @NotNull final LanguageLevel languageLevel) { return new PsiImmediateClassType(resolve, substitutor, languageLevel); } @NotNull - public PsiClassType createType(@NotNull PsiClass resolve, - @NotNull PsiSubstitutor substitutor, - @NotNull LanguageLevel languageLevel, - @NotNull PsiAnnotation[] annotations) { + public PsiClassType createType(@NotNull final PsiClass resolve, + @NotNull final PsiSubstitutor substitutor, + @NotNull final LanguageLevel languageLevel, + @NotNull final PsiAnnotation[] annotations) { return new PsiImmediateClassType(resolve, substitutor, languageLevel, annotations); } @NotNull - public PsiClass createClass(@NotNull String name) throws IncorrectOperationException { - PsiUtil.checkIsIdentifier(myManager, name); - @NonNls String text = "public class " + name + "{ }"; - PsiJavaFile aFile = createDummyJavaFile(text); - PsiClass[] classes = aFile.getClasses(); - if (classes.length != 1) { - throw new IncorrectOperationException(); - } - return classes[0]; + public PsiClass createClass(@NotNull final String name) throws IncorrectOperationException { + return createClassInner("class", name); } @NotNull - public PsiClass createInterface(@NotNull String name) throws IncorrectOperationException { - PsiUtil.checkIsIdentifier(myManager, name); - @NonNls String text = "public interface " + name + "{ }"; - PsiJavaFile aFile = createDummyJavaFile(text); - PsiClass[] classes = aFile.getClasses(); - if (classes.length != 1) { - throw new IncorrectOperationException(); - } - return classes[0]; + public PsiClass createInterface(@NotNull final String name) throws IncorrectOperationException { + return createClassInner("interface", name); } + @NotNull public PsiClass createEnum(@NotNull final String name) throws IncorrectOperationException { + return createClassInner("enum", name); + } + + private PsiClass createClassInner(final String type, final String name) { PsiUtil.checkIsIdentifier(myManager, name); - @NonNls String text = "public enum " + name + "{ }"; - PsiJavaFile aFile = createDummyJavaFile(text); - PsiClass[] classes = aFile.getClasses(); + final PsiJavaFile aFile = createDummyJavaFile(join("public ", type, " ", name, " { }")); + final PsiClass[] classes = aFile.getClasses(); if (classes.length != 1) { - throw new IncorrectOperationException(); + throw new IncorrectOperationException("Incorrect " + type + " name \"" + name + "\"."); } return classes[0]; } @NotNull - public PsiTypeElement createTypeElement(@NotNull PsiType psiType) { + public PsiTypeElement createTypeElement(@NotNull final PsiType psiType) { final LightTypeElement element = new LightTypeElement(myManager, psiType); CodeEditUtil.setNodeGenerated(element.getNode(), true); return element; } @NotNull - public PsiJavaCodeReferenceElement createReferenceElementByType(@NotNull PsiClassType type) { + public PsiJavaCodeReferenceElement createReferenceElementByType(@NotNull final PsiClassType type) { if (type instanceof PsiClassReferenceType) { return ((PsiClassReferenceType)type).getReference(); } final PsiClassType.ClassResolveResult resolveResult = type.resolveGenerics(); - return new LightClassReference(myManager, type.getPresentableText(), resolveResult.getElement(), resolveResult.getSubstitutor()); + final PsiClass refClass = resolveResult.getElement(); + assert refClass != null : type; + return new LightClassReference(myManager, type.getPresentableText(), refClass, resolveResult.getSubstitutor()); } @NotNull - public PsiField createField(@NotNull String name, @NotNull PsiType type) throws IncorrectOperationException { + public PsiField createField(@NotNull final String name, @NotNull final PsiType type) throws IncorrectOperationException { PsiUtil.checkIsIdentifier(myManager, name); if (PsiType.NULL.equals(type)) { - throw new IncorrectOperationException("Cannot create field with type \"\"."); + throw new IncorrectOperationException("Cannot create field with type \"null\"."); } - TreeElement typeCopy = ChangeUtil.copyToElement(createTypeElement(type)); - typeCopy.acceptTree(new GeneratedMarkerVisitor()); - @NonNls String text = "class _Dummy_ {private int " + name + ";}"; - PsiJavaFile aFile = createDummyJavaFile(text); - PsiClass aClass = aFile.getClasses()[0]; - PsiField field = aClass.getFields()[0]; - SourceTreeToPsiMap.psiElementToTree(field).replaceChild(SourceTreeToPsiMap.psiElementToTree(field.getTypeElement()), typeCopy); - ChangeUtil.decodeInformation((TreeElement)SourceTreeToPsiMap.psiElementToTree(field)); + + final PsiJavaFile aFile = createDummyJavaFile(join("class _Dummy_ { private ", type.getCanonicalText(), " ", name, "; }")); + final PsiField field = aFile.getClasses()[0].getFields()[0]; + JavaCodeStyleManager.getInstance(myManager.getProject()).shortenClassReferences(field); return (PsiField)CodeStyleManager.getInstance(myManager.getProject()).reformat(field); } @NotNull - public PsiMethod createMethod(@NotNull String name, PsiType returnType) throws IncorrectOperationException { + public PsiMethod createMethod(@NotNull final String name, final PsiType returnType) throws IncorrectOperationException { PsiUtil.checkIsIdentifier(myManager, name); if (PsiType.NULL.equals(returnType)) { - throw new IncorrectOperationException("Cannot create field with type \"\"."); + throw new IncorrectOperationException("Cannot create method with type \"null\"."); } - @NonNls String text = "class _Dummy_ {\n public " + returnType.getCanonicalText() + " " + name + "(){}\n}"; - PsiJavaFile aFile = createDummyJavaFile(text); - PsiClass aClass = aFile.getClasses()[0]; - PsiMethod method = aClass.getMethods()[0]; + + final PsiJavaFile aFile = createDummyJavaFile(join("class _Dummy_ { public " + returnType.getCanonicalText(), " ", name, "() {} }")); + final PsiMethod method = aFile.getClasses()[0].getMethods()[0]; JavaCodeStyleManager.getInstance(myManager.getProject()).shortenClassReferences(method); return (PsiMethod)CodeStyleManager.getInstance(myManager.getProject()).reformat(method); } @NotNull public PsiMethod createConstructor() { - try { - @NonNls String text = "class _Dummy_ {\n public _Dummy_(){}\n}"; - PsiJavaFile aFile = createDummyJavaFile(text); - PsiClass aClass = aFile.getClasses()[0]; - PsiMethod method = aClass.getMethods()[0]; - return (PsiMethod)CodeStyleManager.getInstance(myManager.getProject()).reformat(method); - } - catch (IncorrectOperationException e) { - LOG.assertTrue(false); - return null; - } + final PsiJavaFile aFile = createDummyJavaFile("class _Dummy_ { public _Dummy_() {} }"); + final PsiMethod method = aFile.getClasses()[0].getMethods()[0]; + return (PsiMethod)CodeStyleManager.getInstance(myManager.getProject()).reformat(method); } @NotNull public PsiClassInitializer createClassInitializer() throws IncorrectOperationException { - @NonNls String text = "class _Dummy_ { {} }"; - final PsiJavaFile aFile = createDummyJavaFile(text); - final PsiClass aClass = aFile.getClasses()[0]; - final PsiClassInitializer psiClassInitializer = aClass.getInitializers()[0]; - return (PsiClassInitializer)CodeStyleManager.getInstance(myManager.getProject()).reformat(psiClassInitializer); + final PsiJavaFile aFile = createDummyJavaFile("class _Dummy_ { {} }"); + final PsiClassInitializer classInitializer = aFile.getClasses()[0].getInitializers()[0]; + return (PsiClassInitializer)CodeStyleManager.getInstance(myManager.getProject()).reformat(classInitializer); } @NotNull - public PsiParameter createParameter(@NotNull String name, @NotNull PsiType type) throws IncorrectOperationException { + public PsiParameter createParameter(@NotNull final String name, @NotNull final PsiType type) throws IncorrectOperationException { PsiUtil.checkIsIdentifier(myManager, name); if (PsiType.NULL.equals(type)) { - throw new IncorrectOperationException("Cannot create field with type \"\"."); + throw new IncorrectOperationException("Cannot create parameter with type \"null\"."); } - final FileElement treeHolder = DummyHolderFactory.createHolder(myManager, null).getTreeElement(); - final String text = type.getCanonicalText() + " " + name; - final CompositeElement treeElement = getJavaParsingContext(treeHolder).getDeclarationParsing().parseParameterText(text); - if (treeElement == null) { - throw new AssertionError("Null element for text = " + text); - } - treeHolder.rawAddChildren(treeElement); - CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myManager.getProject()); - PsiParameter parameter = (PsiParameter)SourceTreeToPsiMap.treeElementToPsi(treeElement); - PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, CodeStyleSettingsManager.getSettings(myManager.getProject()).GENERATE_FINAL_PARAMETERS); - treeElement.acceptTree(new GeneratedMarkerVisitor()); + final String text = join(type.getCanonicalText() + " " + name); + final PsiParameter parameter = createParameterFromText(text, null); + final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myManager.getProject()); + PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, + CodeStyleSettingsManager.getSettings(myManager.getProject()).GENERATE_FINAL_PARAMETERS); + markGenerated(parameter); JavaCodeStyleManager.getInstance(myManager.getProject()).shortenClassReferences(parameter); return (PsiParameter)codeStyleManager.reformat(parameter); } @NotNull public PsiCodeBlock createCodeBlock() { - try { - PsiCodeBlock block = createCodeBlockFromText("{}", null); - return (PsiCodeBlock)CodeStyleManager.getInstance(myManager.getProject()).reformat(block); - } - catch (IncorrectOperationException e) { - LOG.error(e); - return null; - } + final PsiCodeBlock block = createCodeBlockFromText("{}", null); + return (PsiCodeBlock)CodeStyleManager.getInstance(myManager.getProject()).reformat(block); } @NotNull - public PsiClassType createType(@NotNull PsiClass aClass) { + public PsiClassType createType(@NotNull final PsiClass aClass) { return new PsiImmediateClassType(aClass, aClass instanceof PsiTypeParameter ? PsiSubstitutor.EMPTY : createRawSubstitutor(aClass)); } @NotNull - public PsiClassType createType(@NotNull PsiJavaCodeReferenceElement classReference) { + public PsiClassType createType(@NotNull final PsiJavaCodeReferenceElement classReference) { return new PsiClassReferenceType(classReference, null); } @NotNull - public PsiClassType createType(@NotNull PsiClass aClass, PsiType parameter) { - PsiTypeParameter[] typeParameters = aClass.getTypeParameters(); - assert typeParameters.length == 1; - - Map map = Collections.singletonMap(typeParameters[0], parameter); + public PsiClassType createType(@NotNull final PsiClass aClass, final PsiType parameter) { + final PsiTypeParameter[] typeParameters = aClass.getTypeParameters(); + assert typeParameters.length == 1 : aClass; + final Map map = Collections.singletonMap(typeParameters[0], parameter); return createType(aClass, createSubstitutor(map)); } @NotNull - public PsiClassType createType(@NotNull PsiClass aClass, PsiType... parameters) { - PsiTypeParameter[] typeParameters = aClass.getTypeParameters(); + public PsiClassType createType(@NotNull final PsiClass aClass, final PsiType... parameters) { + final PsiTypeParameter[] typeParameters = aClass.getTypeParameters(); assert parameters.length == typeParameters.length; - Map map = new java.util.HashMap(); + final Map map = new java.util.HashMap(); for (int i = 0; i < parameters.length; i++) { map.put(typeParameters[i], parameters[i]); } - return createType(aClass, createSubstitutor(map)); } - private static class TypeDetacher extends PsiTypeVisitor { - public static final TypeDetacher INSTANCE = new TypeDetacher(); - - public PsiType visitType(PsiType type) { - return type; - } - - public PsiType visitWildcardType(PsiWildcardType wildcardType) { - final PsiType bound = wildcardType.getBound(); - if (bound == null) { - return wildcardType; - } - else { - return PsiWildcardType.changeBound(wildcardType, bound.accept(this)); - } - } - - public PsiType visitArrayType(PsiArrayType arrayType) { - final PsiType componentType = arrayType.getComponentType(); - final PsiType detachedComponentType = componentType.accept(this); - if (detachedComponentType == componentType) return arrayType; // optimization - return detachedComponentType.createArrayType(); - } - - public PsiType visitClassType(PsiClassType classType) { - final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); - final PsiClass aClass = resolveResult.getElement(); - if (aClass == null) return classType; - final HashMap map = new HashMap(); - for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(aClass)) { - PsiType type = resolveResult.getSubstitutor().substitute(parameter); - if (type != null) { - type = type.accept(this); - } - map.put(parameter, type); - } - return new PsiImmediateClassType(aClass, PsiSubstitutorImpl.createSubstitutor(map)); - } - } - - @NotNull - public PsiType detachType(@NotNull PsiType type) { - return type.accept(TypeDetacher.INSTANCE); + public PsiType detachType(@NotNull final PsiType type) { + return type; } @NotNull - public PsiSubstitutor createRawSubstitutor(@NotNull PsiTypeParameterListOwner owner) { - Map substMap = null; + public PsiSubstitutor createRawSubstitutor(@NotNull final PsiTypeParameterListOwner owner) { + Map substitutorMap = null; for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(owner)) { - if (substMap == null) substMap = new HashMap(); - substMap.put(parameter, null); + if (substitutorMap == null) substitutorMap = new HashMap(); + substitutorMap.put(parameter, null); } - return PsiSubstitutorImpl.createSubstitutor(substMap); - } - @NotNull - public PsiSubstitutor createRawSubstitutor(@NotNull PsiSubstitutor baseSubstitutor, @NotNull PsiTypeParameter[] typeParameters) { - Map substMap = null; - for (PsiTypeParameter parameter : typeParameters) { - if (substMap == null) substMap = new HashMap(); - substMap.put(parameter, null); - } - return baseSubstitutor.putAll(PsiSubstitutorImpl.createSubstitutor(substMap)); + return PsiSubstitutorImpl.createSubstitutor(substitutorMap); } @NotNull - public PsiElement createDummyHolder(@NotNull String text, @NotNull IElementType type, @Nullable PsiElement context) { + public PsiSubstitutor createRawSubstitutor(@NotNull final PsiSubstitutor baseSubstitutor, @NotNull final PsiTypeParameter[] typeParameters) { + Map substitutorMap = null; + for (PsiTypeParameter parameter : typeParameters) { + if (substitutorMap == null) substitutorMap = new HashMap(); + substitutorMap.put(parameter, null); + } + return baseSubstitutor.putAll(PsiSubstitutorImpl.createSubstitutor(substitutorMap)); + } + + @NotNull + public PsiElement createDummyHolder(@NotNull final String text, @NotNull final IElementType type, @Nullable final PsiElement context) { final DummyHolder result = DummyHolderFactory.createHolder(myManager, context); final FileElement holder = result.getTreeElement(); final Language language = type.getLanguage(); final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(language); - if (parserDefinition == null) { - throw new AssertionError("No parser definition for language " + language); - } + assert parserDefinition != null : "No parser definition for language " + language; final Project project = myManager.getProject(); final Lexer lexer = parserDefinition.createLexer(project); final PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, holder, lexer, language, text); final ASTNode node = parserDefinition.createParser(project).parse(type, builder); holder.rawAddChildren((TreeElement)node); - return node.getPsi(); + final PsiElement psi = node.getPsi(); + assert psi != null : text; + return psi; } @NotNull - public PsiSubstitutor createSubstitutor(@NotNull Map map) { + public PsiSubstitutor createSubstitutor(@NotNull final Map map) { return PsiSubstitutorImpl.createSubstitutor(map); } @Nullable - public PsiPrimitiveType createPrimitiveType(@NotNull String text) { - return getPrimitiveType(text); - } - - public static PsiPrimitiveType getPrimitiveType(final String text) { - return ourPrimitiveTypesMap.get(text); + public PsiPrimitiveType createPrimitiveType(@NotNull final String text) { + return PsiJavaParserFacadeImpl.getPrimitiveType(text); } @NotNull - public PsiClassType createTypeByFQClassName(@NotNull String qName) { + public PsiClassType createTypeByFQClassName(@NotNull final String qName) { return createTypeByFQClassName(qName, GlobalSearchScope.allScope(myManager.getProject())); } @NotNull - public PsiClassType createTypeByFQClassName(@NotNull String qName, @NotNull GlobalSearchScope resolveScope) { + public PsiClassType createTypeByFQClassName(@NotNull final String qName, @NotNull final GlobalSearchScope resolveScope) { return new PsiClassReferenceType(createReferenceElementByFQClassName(qName, resolveScope), null); } @NotNull - public PsiJavaCodeReferenceElement createClassReferenceElement(@NotNull PsiClass aClass) { + public PsiJavaCodeReferenceElement createClassReferenceElement(@NotNull final PsiClass aClass) { final String text; if (aClass instanceof PsiAnonymousClass) { text = ((PsiAnonymousClass)aClass).getBaseClassType().getPresentableText(); @@ -421,19 +326,20 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiJavaCodeReferenceElement createReferenceElementByFQClassName(@NotNull String qName, @NotNull GlobalSearchScope resolveScope) { - String shortName = PsiNameHelper.getShortClassName(qName); + public PsiJavaCodeReferenceElement createReferenceElementByFQClassName(@NotNull final String qName, + @NotNull final GlobalSearchScope resolveScope) { + final String shortName = PsiNameHelper.getShortClassName(qName); return new LightClassReference(myManager, shortName, qName, resolveScope); } @NotNull - public PsiJavaCodeReferenceElement createFQClassNameReferenceElement(@NotNull String qName, @NotNull GlobalSearchScope resolveScope) { + public PsiJavaCodeReferenceElement createFQClassNameReferenceElement(@NotNull final String qName, + @NotNull final GlobalSearchScope resolveScope) { return new LightClassReference(myManager, qName, qName, resolveScope); } @NotNull - public PsiJavaCodeReferenceElement createPackageReferenceElement(@NotNull PsiPackage aPackage) - throws IncorrectOperationException { + public PsiJavaCodeReferenceElement createPackageReferenceElement(@NotNull final PsiPackage aPackage) throws IncorrectOperationException { if (aPackage.getQualifiedName().length() == 0) { throw new IncorrectOperationException("Cannot create reference to default package."); } @@ -441,18 +347,20 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiPackageStatement createPackageStatement(@NotNull String name) throws IncorrectOperationException { - final PsiJavaFile javaFile = (PsiJavaFile)PsiFileFactory.getInstance(myManager.getProject()).createFileFromText("dummy.java", "package " + name + ";"); - final PsiPackageStatement stmt = javaFile.getPackageStatement(); - if (stmt == null) throw new IncorrectOperationException("Incorrect package name: " + name); + public PsiPackageStatement createPackageStatement(@NotNull final String name) throws IncorrectOperationException { + final PsiJavaFile aFile = createDummyJavaFile(join("package ", name, ";")); + final PsiPackageStatement stmt = aFile.getPackageStatement(); + if (stmt == null) { + throw new IncorrectOperationException("Incorrect package name: " + name); + } return stmt; } @NotNull - public PsiJavaCodeReferenceCodeFragment createReferenceCodeFragment(@NotNull String text, - PsiElement context, - boolean isPhysical, - boolean isClassesAccepted) { + public PsiJavaCodeReferenceCodeFragment createReferenceCodeFragment(@NotNull final String text, + final PsiElement context, + final boolean isPhysical, + final boolean isClassesAccepted) { final PsiJavaCodeReferenceCodeFragmentImpl result = new PsiJavaCodeReferenceCodeFragmentImpl(myManager.getProject(), isPhysical, "fragment.java", text, isClassesAccepted); result.setContext(context); @@ -460,51 +368,54 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiImportStaticStatement createImportStaticStatement(@NotNull PsiClass aClass, @NotNull String memberName) throws IncorrectOperationException { + public PsiImportStaticStatement createImportStaticStatement(@NotNull final PsiClass aClass, + @NotNull final String memberName) throws IncorrectOperationException { if (aClass instanceof PsiAnonymousClass) { throw new IncorrectOperationException("Cannot create import statement for anonymous class."); } else if (aClass.getParent() instanceof PsiDeclarationStatement) { throw new IncorrectOperationException("Cannot create import statement for local class."); } - @NonNls String text = "import static " + aClass.getQualifiedName() + "." + memberName + ";"; - PsiJavaFile aFile = createDummyJavaFile(text); - PsiImportStaticStatement statement = aFile.getImportList().getImportStaticStatements()[0]; + + final PsiJavaFile aFile = createDummyJavaFile(join("import static ", aClass.getQualifiedName(), ".", memberName, ";")); + final PsiImportStatementBase statement = extractImport(aFile, true); return (PsiImportStaticStatement)CodeStyleManager.getInstance(myManager.getProject()).reformat(statement); } @NotNull - public PsiParameterList createParameterList(@NotNull String[] names, @NotNull PsiType[] types) throws IncorrectOperationException { - @NonNls String text = "void method("; - String sep = ""; - for (int i = 0; i < names.length; i++) { - final String name = names[i]; - PsiType type = types[i]; - text += sep + type.getCanonicalText() + " " + name; - sep = ","; + public PsiParameterList createParameterList(@NotNull final String[] names, @NotNull final PsiType[] types) throws IncorrectOperationException { + final StringBuilder builder = StringBuilderSpinAllocator.alloc(); + try { + builder.append("void method("); + for (int i = 0; i < names.length; i++) { + if (i > 0) builder.append(", "); + builder.append(types[i].getCanonicalText()).append(' ').append(names[i]); + } + return createMethodFromText(builder.toString(), null).getParameterList(); + } + finally { + StringBuilderSpinAllocator.dispose(builder); } - text += "){}"; - PsiMethod method = createMethodFromText(text, null); - return method.getParameterList(); } @NotNull - public PsiReferenceList createReferenceList(@NotNull PsiJavaCodeReferenceElement[] references) throws IncorrectOperationException { - @NonNls String text = "void method() "; - if (references.length > 0) text += "throws "; - String sep = ""; - for (final PsiJavaCodeReferenceElement reference : references) { - text += sep + reference.getCanonicalText(); - sep = ","; + public PsiReferenceList createReferenceList(@NotNull final PsiJavaCodeReferenceElement[] references) throws IncorrectOperationException { + final StringBuilder builder = StringBuilderSpinAllocator.alloc(); + try { + builder.append("void method() throws "); + for (int i = 0; i < references.length; i++) { + if (i > 0) builder.append(", "); + builder.append(references[i].getCanonicalText()); + } + return createMethodFromText(builder.toString(), null).getThrowsList(); + } + finally { + StringBuilderSpinAllocator.dispose(builder); } - text += "{}"; - PsiMethod method = createMethodFromText(text, null); - return method.getThrowsList(); } @NotNull - public PsiJavaCodeReferenceElement createPackageReferenceElement(@NotNull String packageName) - throws IncorrectOperationException { + public PsiJavaCodeReferenceElement createPackageReferenceElement(@NotNull final String packageName) throws IncorrectOperationException { if (packageName.length() == 0) { throw new IncorrectOperationException("Cannot create reference to default package."); } @@ -512,8 +423,8 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiReferenceExpression createReferenceExpression(@NotNull PsiClass aClass) throws IncorrectOperationException { - String text; + public PsiReferenceExpression createReferenceExpression(@NotNull final PsiClass aClass) throws IncorrectOperationException { + final String text; if (aClass instanceof PsiAnonymousClass) { text = ((PsiAnonymousClass)aClass).getBaseClassType().getPresentableText(); } @@ -524,7 +435,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiReferenceExpression createReferenceExpression(@NotNull PsiPackage aPackage) throws IncorrectOperationException { + public PsiReferenceExpression createReferenceExpression(@NotNull final PsiPackage aPackage) throws IncorrectOperationException { if (aPackage.getQualifiedName().length() == 0) { throw new IncorrectOperationException("Cannot create reference to default package."); } @@ -532,13 +443,13 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiIdentifier createIdentifier(@NotNull String text) throws IncorrectOperationException { + public PsiIdentifier createIdentifier(@NotNull final String text) throws IncorrectOperationException { PsiUtil.checkIsIdentifier(myManager, text); return new LightIdentifier(myManager, text); } @NotNull - public PsiKeyword createKeyword(@NotNull String text) throws IncorrectOperationException { + public PsiKeyword createKeyword(@NotNull final String text) throws IncorrectOperationException { if (!JavaPsiFacade.getInstance(myManager.getProject()).getNameHelper().isKeyword(text)) { throw new IncorrectOperationException("\"" + text + "\" is not a keyword."); } @@ -546,21 +457,21 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiImportStatement createImportStatement(@NotNull PsiClass aClass) throws IncorrectOperationException { + public PsiImportStatement createImportStatement(@NotNull final PsiClass aClass) throws IncorrectOperationException { if (aClass instanceof PsiAnonymousClass) { throw new IncorrectOperationException("Cannot create import statement for anonymous class."); } else if (aClass.getParent() instanceof PsiDeclarationStatement) { throw new IncorrectOperationException("Cannot create import statement for local class."); } - @NonNls String text = "import " + aClass.getQualifiedName() + ";"; - PsiJavaFile aFile = createDummyJavaFile(text); - PsiImportStatement statement = aFile.getImportList().getImportStatements()[0]; + + final PsiJavaFile aFile = createDummyJavaFile(join("import ", aClass.getQualifiedName(), ";")); + final PsiImportStatementBase statement = extractImport(aFile, false); return (PsiImportStatement)CodeStyleManager.getInstance(myManager.getProject()).reformat(statement); } @NotNull - public PsiImportStatement createImportStatementOnDemand(@NotNull String packageName) throws IncorrectOperationException { + public PsiImportStatement createImportStatementOnDemand(@NotNull final String packageName) throws IncorrectOperationException { if (packageName.length() == 0) { throw new IncorrectOperationException("Cannot create import statement for default package."); } @@ -568,102 +479,103 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps throw new IncorrectOperationException("Incorrect package name: \"" + packageName + "\"."); } - @NonNls String text = "import " + packageName + ".*;"; - PsiJavaFile aFile = createDummyJavaFile(text); - PsiImportStatement statement = aFile.getImportList().getImportStatements()[0]; + final PsiJavaFile aFile = createDummyJavaFile(join("import ", packageName, ".*;")); + final PsiImportStatementBase statement = extractImport(aFile, false); return (PsiImportStatement)CodeStyleManager.getInstance(myManager.getProject()).reformat(statement); } @NotNull - public PsiDeclarationStatement createVariableDeclarationStatement(@NotNull String name, @NotNull PsiType type, PsiExpression initializer) - throws IncorrectOperationException { + public PsiDeclarationStatement createVariableDeclarationStatement(@NotNull final String name, + @NotNull final PsiType type, + final PsiExpression initializer) throws IncorrectOperationException { if (!JavaPsiFacade.getInstance(myManager.getProject()).getNameHelper().isIdentifier(name)) { throw new IncorrectOperationException("\"" + name + "\" is not an identifier."); } if (PsiType.NULL.equals(type)) { - throw new IncorrectOperationException("Cannot create field with type \"\"."); + throw new IncorrectOperationException("Cannot create variable with type \"null\"."); } - @NonNls StringBuilder buffer = new StringBuilder(); - buffer.append("X "); - buffer.append(name); + + final StringBuilder builder = StringBuilderSpinAllocator.alloc(); + builder.append("X ").append(name); if (initializer != null) { - buffer.append("=x"); + builder.append(" = x"); } - buffer.append(";"); - PsiDeclarationStatement statement = (PsiDeclarationStatement)createStatementFromText(buffer.toString(), null); - PsiVariable variable = (PsiVariable)statement.getDeclaredElements()[0]; - variable.getTypeElement().replace(createTypeElement(type)); - PsiUtil.setModifierProperty(variable, PsiModifier.FINAL, CodeStyleSettingsManager.getSettings(myManager.getProject()).GENERATE_FINAL_LOCALS); + builder.append(';'); + final String text = builder.toString(); + StringBuilderSpinAllocator.dispose(builder); + + final PsiDeclarationStatement statement = (PsiDeclarationStatement)createStatementFromText(text, null); + final PsiVariable variable = (PsiVariable)statement.getDeclaredElements()[0]; + replace(variable.getTypeElement(), createTypeElement(type), text); + PsiUtil.setModifierProperty(variable, PsiModifier.FINAL, + CodeStyleSettingsManager.getSettings(myManager.getProject()).GENERATE_FINAL_LOCALS); if (initializer != null) { - variable.getInitializer().replace(initializer); + replace(variable.getInitializer(), initializer, text); } markGenerated(statement); return statement; - } @NotNull - public PsiDocTag createParamTag(@NotNull String parameterName, @NonNls String description) throws IncorrectOperationException { - @NonNls StringBuilder buffer = new StringBuilder(); - buffer.append(" * @param "); - buffer.append(parameterName); - buffer.append(" "); - final String[] strings = description.split("\\n"); - for (int i = 0; i < strings.length; i++) { - String string = strings[i]; - if (i > 0) buffer.append("\n * "); - buffer.append(string); + public PsiDocTag createParamTag(@NotNull final String parameterName, @NonNls final String description) throws IncorrectOperationException { + final StringBuilder builder = StringBuilderSpinAllocator.alloc(); + try { + builder.append(" * @param "); + builder.append(parameterName); + builder.append(" "); + final String[] strings = description.split("\\n"); + for (int i = 0; i < strings.length; i++) { + if (i > 0) builder.append("\n * "); + builder.append(strings[i]); + } + return createDocTagFromText(builder.toString()); + } + finally { + StringBuilderSpinAllocator.dispose(builder); } - return createDocTagFromText(buffer.toString(), null); } @NotNull - public PsiExpressionCodeFragment createExpressionCodeFragment(@NotNull String text, - PsiElement context, + public PsiExpressionCodeFragment createExpressionCodeFragment(@NotNull final String text, + final PsiElement context, final PsiType expectedType, - boolean isPhysical) { - final PsiExpressionCodeFragmentImpl result = new PsiExpressionCodeFragmentImpl( - myManager.getProject(), isPhysical, "fragment.java", text, expectedType); + final boolean isPhysical) { + final PsiExpressionCodeFragmentImpl result = + new PsiExpressionCodeFragmentImpl(myManager.getProject(), isPhysical, "fragment.java", text, expectedType); result.setContext(context); return result; } @NotNull - public JavaCodeFragment createCodeBlockCodeFragment(@NotNull String text, PsiElement context, boolean isPhysical) { - final PsiCodeFragmentImpl result = new PsiCodeFragmentImpl(myManager.getProject(), JavaElementType.STATEMENTS, - isPhysical, - "fragment.java", - text); + public JavaCodeFragment createCodeBlockCodeFragment(@NotNull final String text, final PsiElement context, final boolean isPhysical) { + final PsiCodeFragmentImpl result = + new PsiCodeFragmentImpl(myManager.getProject(), JavaElementType.STATEMENTS, isPhysical, "fragment.java", text); result.setContext(context); return result; } @NotNull - public PsiTypeCodeFragment createTypeCodeFragment(@NotNull String text, PsiElement context, boolean isPhysical) { - + public PsiTypeCodeFragment createTypeCodeFragment(@NotNull final String text, final PsiElement context, final boolean isPhysical) { return createTypeCodeFragment(text, context, false, isPhysical, false); } @NotNull - public PsiTypeCodeFragment createTypeCodeFragment(@NotNull String text, - PsiElement context, - boolean isVoidValid, - boolean isPhysical) { + public PsiTypeCodeFragment createTypeCodeFragment(@NotNull final String text, + final PsiElement context, + final boolean isVoidValid, + final boolean isPhysical) { return createTypeCodeFragment(text, context, true, isPhysical, false); } @NotNull - public PsiTypeCodeFragment createTypeCodeFragment(@NotNull String text, - PsiElement context, - boolean isVoidValid, - boolean isPhysical, - boolean allowEllipsis) { - final PsiTypeCodeFragmentImpl result = new PsiTypeCodeFragmentImpl(myManager.getProject(), - isPhysical, - allowEllipsis, - "fragment.java", - text); + public PsiTypeCodeFragment createTypeCodeFragment(@NotNull final String text, + final PsiElement context, + final boolean isVoidValid, + final boolean isPhysical, + final boolean allowEllipsis) { + final PsiTypeCodeFragmentImpl result + = new PsiTypeCodeFragmentImpl(myManager.getProject(), isPhysical, allowEllipsis, "fragment.java", text); result.setContext(context); if (isVoidValid) { result.putUserData(PsiUtil.VALID_VOID_TYPE_IN_CODE_FRAGMENT, Boolean.TRUE); @@ -671,7 +583,6 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps return result; } - @NotNull public PsiAnnotation createAnnotationFromText(@NotNull final String annotationText, final PsiElement context) throws IncorrectOperationException { final PsiAnnotation psiAnnotation = super.createAnnotationFromText(annotationText, context); @@ -727,8 +638,8 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiTypeParameter createTypeParameterFromText(@NotNull final String text, final PsiElement context) throws - IncorrectOperationException { + public PsiTypeParameter createTypeParameterFromText(@NotNull final String text, + final PsiElement context) throws IncorrectOperationException { final PsiTypeParameter typeParameter = super.createTypeParameterFromText(text, context); markGenerated(typeParameter); return typeParameter; @@ -742,18 +653,18 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } @NotNull - public PsiMethod createMethodFromText(@NotNull final String text, final PsiElement context, final LanguageLevel level) throws - IncorrectOperationException { + public PsiMethod createMethodFromText(@NotNull final String text, + final PsiElement context, + final LanguageLevel level) throws IncorrectOperationException { final PsiMethod method = super.createMethodFromText(text, context, level); markGenerated(method); return method; } - @NotNull public PsiCatchSection createCatchSection(@NotNull final PsiClassType exceptionType, - @NotNull final String exceptionName, final PsiElement context) throws - IncorrectOperationException { + @NotNull final String exceptionName, + final PsiElement context) throws IncorrectOperationException { final PsiCatchSection psiCatchSection = super.createCatchSection(exceptionType, exceptionName, context); markGenerated(psiCatchSection); return psiCatchSection; @@ -762,4 +673,25 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps private static void markGenerated(final PsiElement element) { ((TreeElement)element.getNode()).acceptTree(new GeneratedMarkerVisitor()); } + + private static PsiImportStatementBase extractImport(final PsiJavaFile aFile, final boolean isStatic) { + final PsiImportList importList = aFile.getImportList(); + assert importList != null : aFile; + final PsiImportStatementBase[] statements = isStatic ? importList.getImportStaticStatements() : importList.getImportStatements(); + assert statements.length == 1 : aFile.getText(); + return statements[0]; + } + + private static void replace(final PsiElement original, final PsiElement replacement, final String message) { + assert original != null : message; + original.replace(replacement); + } + + /** + * @deprecated use {@link PsiJavaParserFacadeImpl#getPrimitiveType(String)} (remove in IDEA 11). + */ + @SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass", "UnusedDeclaration"}) + public static PsiPrimitiveType getPrimitiveType(final String text) { + return PsiJavaParserFacadeImpl.getPrimitiveType(text); + } } diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java index 79bf4d8f2303..acc40b73b1a5 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java @@ -14,14 +14,13 @@ * limitations under the License. */ -/* - * @author max - */ package com.intellij.psi.impl; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.JavaTemplateUtil; +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.java.parser.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; @@ -29,79 +28,154 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; +import com.intellij.psi.impl.source.DummyHolder; import com.intellij.psi.impl.source.DummyHolderFactory; +import com.intellij.psi.impl.source.JavaDummyElement; import com.intellij.psi.impl.source.SourceTreeToPsiMap; -import com.intellij.psi.impl.source.parsing.DeclarationParsing; -import com.intellij.psi.impl.source.parsing.ExpressionParsing; -import com.intellij.psi.impl.source.parsing.JavaParsingContext; -import com.intellij.psi.impl.source.parsing.Parsing; -import com.intellij.psi.impl.source.tree.CompositeElement; -import com.intellij.psi.impl.source.tree.FileElement; -import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTag; -import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.HashMap; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.util.Map; import java.util.Properties; +import static com.intellij.openapi.util.text.StringUtil.join; + +/* + * @author max + */ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJavaParserFacade { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiJavaParserFacadeImpl"); - protected static final Map ourPrimitiveTypesMap = new HashMap(); - protected PsiJavaFile myDummyJavaFile; + private static final JavaParserUtil.ParserWrapper ANNOTATION = new JavaParserUtil.ParserWrapper() { + @Override + public void parse(final PsiBuilder builder) { + DeclarationParser.parseAnnotation(builder); + } + }; - public PsiJavaParserFacadeImpl(PsiManagerEx manager) { + private static final JavaParserUtil.ParserWrapper PARAMETER = new JavaParserUtil.ParserWrapper() { + @Override + public void parse(final PsiBuilder builder) { + DeclarationParser.parseParameter(builder, true); + } + }; + + private static final JavaParserUtil.ParserWrapper TYPE = new JavaParserUtil.ParserWrapper() { + @Override + public void parse(final PsiBuilder builder) { + ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.ELLIPSIS | ReferenceParser.WILDCARD); + } + }; + + private static final JavaParserUtil.ParserWrapper TYPE_PARAMETER = new JavaParserUtil.ParserWrapper() { + @Override + public void parse(final PsiBuilder builder) { + ReferenceParser.parseTypeParameter(builder); + } + }; + + private static final JavaParserUtil.ParserWrapper DECLARATION = new JavaParserUtil.ParserWrapper() { + @Override + public void parse(final PsiBuilder builder) { + DeclarationParser.parse(builder, DeclarationParser.Context.CLASS); + } + }; + + private static final JavaParserUtil.ParserWrapper CODE_BLOCK = new JavaParserUtil.ParserWrapper() { + @Override + public void parse(final PsiBuilder builder) { + StatementParser.parseCodeBlockDeep(builder, true); + } + }; + + private static final JavaParserUtil.ParserWrapper STATEMENT = new JavaParserUtil.ParserWrapper() { + @Override + public void parse(final PsiBuilder builder) { + StatementParser.parseStatement(builder); + } + }; + + private static final JavaParserUtil.ParserWrapper EXPRESSION = new JavaParserUtil.ParserWrapper() { + @Override + public void parse(final PsiBuilder builder) { + ExpressionParser.parse(builder); + } + }; + + private static final JavaParserUtil.ParserWrapper ENUM_CONSTANT = new JavaParserUtil.ParserWrapper() { + @Override + public void parse(final PsiBuilder builder) { + DeclarationParser.parseEnumConstant(builder); + } + }; + + private static final JavaParserUtil.ParserWrapper CATCH_SECTION = new JavaParserUtil.ParserWrapper() { + @Override + public void parse(final PsiBuilder builder) { + StatementParser.parseCatchBlock(builder); + } + }; + + private static final Map PRIMITIVE_TYPES; + static { + PRIMITIVE_TYPES = new HashMap(); + PRIMITIVE_TYPES.put(PsiType.BYTE.getCanonicalText(), PsiType.BYTE); + PRIMITIVE_TYPES.put(PsiType.CHAR.getCanonicalText(), PsiType.CHAR); + PRIMITIVE_TYPES.put(PsiType.DOUBLE.getCanonicalText(), PsiType.DOUBLE); + PRIMITIVE_TYPES.put(PsiType.FLOAT.getCanonicalText(), PsiType.FLOAT); + PRIMITIVE_TYPES.put(PsiType.INT.getCanonicalText(), PsiType.INT); + PRIMITIVE_TYPES.put(PsiType.LONG.getCanonicalText(), PsiType.LONG); + PRIMITIVE_TYPES.put(PsiType.SHORT.getCanonicalText(), PsiType.SHORT); + PRIMITIVE_TYPES.put(PsiType.BOOLEAN.getCanonicalText(), PsiType.BOOLEAN); + PRIMITIVE_TYPES.put(PsiType.VOID.getCanonicalText(), PsiType.VOID); + PRIMITIVE_TYPES.put(PsiType.NULL.getCanonicalText(), PsiType.NULL); + } + + public PsiJavaParserFacadeImpl(final PsiManagerEx manager) { super(manager); } @NotNull - public PsiAnnotation createAnnotationFromText(@NotNull String annotationText, PsiElement context) throws IncorrectOperationException { - final FileElement holderElement = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - CompositeElement annotationElement = getJavaParsingContext(holderElement).getDeclarationParsing().parseAnnotationFromText(myManager, annotationText, getLanguageLevel(context)); - if (annotationElement == null || annotationElement.getElementType() != JavaElementType.ANNOTATION) { - throw new IncorrectOperationException("Incorrect annotation \"" + annotationText + "\"."); + public PsiAnnotation createAnnotationFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, ANNOTATION, false), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiAnnotation)) { + throw new IncorrectOperationException("Incorrect annotation \"" + text + "\"."); } - holderElement.rawAddChildren(annotationElement); - return (PsiAnnotation)SourceTreeToPsiMap.treeElementToPsi(annotationElement); - } - - private LanguageLevel getLanguageLevel(final PsiElement context) { - if (context == null) { - return LanguageLevelProjectExtension.getInstance(myManager.getProject()).getLanguageLevel(); - } - return PsiUtil.getLanguageLevel(context); + return (PsiAnnotation)element; } @NotNull - public PsiDocTag createDocTagFromText(@NotNull String docTagText, PsiElement context) throws IncorrectOperationException { - StringBuilder buffer = new StringBuilder(); - buffer.append("/**\n"); - buffer.append(docTagText); - buffer.append("\n */"); - PsiDocComment comment = createDocCommentFromText(buffer.toString(), context); - return comment.getTags()[0]; + public PsiDocTag createDocTagFromText(@NotNull final String text) throws IncorrectOperationException { + return createDocCommentFromText(join("/**\n", text, "\n */")).getTags()[0]; } @NotNull - public PsiDocComment createDocCommentFromText(@NotNull String docCommentText, PsiElement context) throws IncorrectOperationException { - @NonNls StringBuilder buffer = new StringBuilder(); - buffer.append(docCommentText); - buffer.append("void m();"); - final PsiMethod method = createMethodFromText(buffer.toString(), null); - return method.getDocComment(); + public PsiDocTag createDocTagFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + return createDocTagFromText(text); } @NotNull - public PsiClass createClassFromText(@NotNull String body, PsiElement context) throws IncorrectOperationException { - @NonNls String fileText = "class _Dummy_ { " + body + " }"; - PsiJavaFile aFile = createDummyJavaFile(fileText); - PsiClass[] classes = aFile.getClasses(); + public PsiDocComment createDocCommentFromText(@NotNull final String text) throws IncorrectOperationException { + final PsiMethod method = createMethodFromText(join(text, "void m();"), null); + final PsiDocComment comment = method.getDocComment(); + assert comment != null : text; + return comment; + } + + @NotNull + public PsiDocComment createDocCommentFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + return createDocCommentFromText(text); + } + + @NotNull + public PsiClass createClassFromText(@NotNull final String body, final PsiElement context) throws IncorrectOperationException { + final PsiJavaFile aFile = createDummyJavaFile(join("class _Dummy_ { ", body, " }")); + final PsiClass[] classes = aFile.getClasses(); if (classes.length != 1) { throw new IncorrectOperationException("Incorrect class \"" + body + "\"."); } @@ -109,211 +183,186 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull - public PsiField createFieldFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException { - final FileElement holderElement = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - TreeElement decl = getJavaParsingContext(holderElement).getDeclarationParsing().parseDeclarationText(myManager, LanguageLevelProjectExtension - .getInstance(myManager.getProject()).getLanguageLevel(), text, DeclarationParsing.Context.CLASS_CONTEXT); - if (decl == null || decl.getElementType() != JavaElementType.FIELD) { + public PsiField createFieldFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, DECLARATION, false), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiField)) { throw new IncorrectOperationException("Incorrect field \"" + text + "\"."); } - holderElement.rawAddChildren(decl); - return (PsiField)SourceTreeToPsiMap.treeElementToPsi(decl); - } - - protected JavaParsingContext getJavaParsingContext (FileElement holderElement) { - return new JavaParsingContext(holderElement.getCharTable(), LanguageLevelProjectExtension.getInstance(myManager.getProject()).getLanguageLevel()); - } - - private static JavaParsingContext getJavaParsingContext (FileElement holderElement, LanguageLevel languageLevel) { - return new JavaParsingContext(holderElement.getCharTable(), languageLevel); + return (PsiField)element; } @NotNull - public PsiMethod createMethodFromText(@NotNull String text, PsiElement context, LanguageLevel level) throws IncorrectOperationException { - final FileElement holderElement = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - TreeElement decl = getJavaParsingContext(holderElement, level).getDeclarationParsing().parseDeclarationText(myManager, level, text, - DeclarationParsing.Context.CLASS_CONTEXT); - if (decl == null || decl.getElementType() != JavaElementType.METHOD) { - throw new IncorrectOperationException("Incorrect method '" + text + "'. Context:"+context+"; Level:"+level+"; parsed: "+(decl == null ? null : DebugUtil.treeToString(decl, false))); + public PsiMethod createMethodFromText(@NotNull final String text, final PsiElement context, final LanguageLevel level) + throws IncorrectOperationException { + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, DECLARATION, false, level), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiMethod)) { + throw new IncorrectOperationException("Incorrect method \"" + text + "\"."); } - holderElement.rawAddChildren(decl); - return (PsiMethod)SourceTreeToPsiMap.treeElementToPsi(decl); + return (PsiMethod)element; } @NotNull - public final PsiMethod createMethodFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException { - return createMethodFromText(text, context, LanguageLevelProjectExtension.getInstance(myManager.getProject()).getLanguageLevel()); + public final PsiMethod createMethodFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final LanguageLevel level = LanguageLevelProjectExtension.getInstance(myManager.getProject()).getLanguageLevel(); + return createMethodFromText(text, context, level); } @NotNull - public PsiParameter createParameterFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException { - final FileElement holderElement = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - CompositeElement param = getJavaParsingContext(holderElement).getDeclarationParsing().parseParameterText(text); - if (param == null) { + public PsiParameter createParameterFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, PARAMETER, false), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiParameter)) { throw new IncorrectOperationException("Incorrect parameter \"" + text + "\"."); } - holderElement.rawAddChildren(param); - return (PsiParameter)SourceTreeToPsiMap.treeElementToPsi(param); + return (PsiParameter)element; } @NotNull - public PsiType createTypeFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException { + public PsiType createTypeFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { return createTypeInner(text, context, false); } - protected PsiType createTypeInner(final String text, final PsiElement context, boolean markAsCopy) throws IncorrectOperationException { - PsiPrimitiveType primitiveType = ourPrimitiveTypesMap.get(text); + protected PsiType createTypeInner(final String text, final PsiElement context, final boolean markAsCopy) throws IncorrectOperationException { + final PsiPrimitiveType primitiveType = PRIMITIVE_TYPES.get(text); if (primitiveType != null) return primitiveType; - final FileElement holderElement = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - CompositeElement typeElement = Parsing.parseTypeText(myManager, text, 0, text.length(), holderElement.getCharTable()); - if (typeElement == null) { - throw new IncorrectOperationException("Incorrect type \"" + text + "\""); + + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, TYPE, false), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiTypeElement)) { + throw new IncorrectOperationException("Incorrect type \"" + text + "\"."); } - holderElement.rawAddChildren(typeElement); + if (markAsCopy) { - holderElement.acceptTree(new GeneratedMarkerVisitor()); + holder.getTreeElement().acceptTree(new GeneratedMarkerVisitor()); } - PsiTypeElement psiTypeElement = (PsiTypeElement)SourceTreeToPsiMap.treeElementToPsi(typeElement); - if (psiTypeElement == null) { - throw new IncorrectOperationException("PSI is null for element "+typeElement); - } - return psiTypeElement.getType(); + + return ((PsiTypeElement)element).getType(); } @NotNull - public PsiCodeBlock createCodeBlockFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException { - final FileElement holderElement = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - CompositeElement treeElement = getJavaParsingContext(holderElement).getStatementParsing().parseCodeBlockText(myManager, text); - if (treeElement == null) { + public PsiCodeBlock createCodeBlockFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, CODE_BLOCK, true), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiCodeBlock)) { throw new IncorrectOperationException("Incorrect code block \"" + text + "\"."); } - holderElement.rawAddChildren(treeElement); - return (PsiCodeBlock)SourceTreeToPsiMap.treeElementToPsi(treeElement); + return (PsiCodeBlock)element; } @NotNull - public PsiStatement createStatementFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException { - final FileElement treeHolder = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - TreeElement treeElement = getJavaParsingContext(treeHolder).getStatementParsing().parseStatementText(text); - if (treeElement == null) { + public PsiStatement createStatementFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, STATEMENT, false), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiStatement)) { throw new IncorrectOperationException("Incorrect statement \"" + text + "\"."); } - treeHolder.rawAddChildren(treeElement); - return (PsiStatement)SourceTreeToPsiMap.treeElementToPsi(treeElement); + return (PsiStatement)element; } @NotNull - public PsiExpression createExpressionFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException { - final FileElement treeHolder = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - final CompositeElement treeElement = ExpressionParsing.parseExpressionText(myManager, text, 0, - text.length(), treeHolder.getCharTable()); - if (treeElement == null) { + public PsiExpression createExpressionFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, EXPRESSION, false), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiExpression)) { throw new IncorrectOperationException("Incorrect expression \"" + text + "\"."); } - treeHolder.rawAddChildren(treeElement); - return (PsiExpression)SourceTreeToPsiMap.treeElementToPsi(treeElement); + return (PsiExpression)element; } - protected PsiJavaFile createDummyJavaFile(String text) { - String ext = StdFileTypes.JAVA.getDefaultExtension(); - @NonNls String fileName = "_Dummy_." + ext; - FileType type = StdFileTypes.JAVA; - + protected PsiJavaFile createDummyJavaFile(final String text) { + final String fileName = "_Dummy_." + StdFileTypes.JAVA.getDefaultExtension(); + final FileType type = StdFileTypes.JAVA; return (PsiJavaFile)PsiFileFactory.getInstance(myManager.getProject()).createFileFromText(type, fileName, text, 0, text.length()); } @NotNull - public PsiTypeParameter createTypeParameterFromText(@NotNull String text, PsiElement context) - throws IncorrectOperationException { - final FileElement holderElement = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - TreeElement treeElement = getJavaParsingContext(holderElement).getDeclarationParsing().parseTypeParameterText(text); - if (treeElement == null) { - throw new IncorrectOperationException("Incorrect type parameter \"" + text + "\""); + public PsiTypeParameter createTypeParameterFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, TYPE_PARAMETER, false), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiTypeParameter)) { + throw new IncorrectOperationException("Incorrect type parameter \"" + text + "\"."); } - holderElement.rawAddChildren(treeElement); - return (PsiTypeParameter)SourceTreeToPsiMap.treeElementToPsi(treeElement); + return (PsiTypeParameter)element; } @NotNull - public PsiComment createCommentFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException { - PsiJavaFile aFile = createDummyJavaFile(text); - PsiElement[] children = aFile.getChildren(); - for (PsiElement aChildren : children) { + public PsiComment createCommentFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final PsiJavaFile aFile = createDummyJavaFile(text); + for (PsiElement aChildren : aFile.getChildren()) { if (aChildren instanceof PsiComment) { if (!aChildren.getText().equals(text)) { - throw new IncorrectOperationException("Incorrect comment \"" + text + "\"."); + break; } - PsiComment comment = (PsiComment)aChildren; + final PsiComment comment = (PsiComment)aChildren; DummyHolderFactory.createHolder(myManager, (TreeElement)SourceTreeToPsiMap.psiElementToTree(comment), context); return comment; } } + throw new IncorrectOperationException("Incorrect comment \"" + text + "\"."); } @NotNull - public PsiEnumConstant createEnumConstantFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException { - final FileElement holderElement = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - TreeElement decl = getJavaParsingContext(holderElement).getDeclarationParsing().parseEnumConstantText(text); - if (decl == null || decl.getElementType() != JavaElementType.ENUM_CONSTANT) { - throw new IncorrectOperationException("Incorrect enum constant text \"" + text + "\"."); + public PsiEnumConstant createEnumConstantFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, ENUM_CONSTANT, false), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiEnumConstant)) { + throw new IncorrectOperationException("Incorrect enum constant \"" + text + "\"."); } - holderElement.rawAddChildren(decl); - return (PsiEnumConstant)SourceTreeToPsiMap.treeElementToPsi(decl); + return (PsiEnumConstant)element; } @NotNull - public PsiCatchSection createCatchSection(@NotNull PsiClassType exceptionType, - @NotNull String exceptionName, - PsiElement context) throws IncorrectOperationException { - @NonNls StringBuilder buffer = new StringBuilder(); - buffer.append("catch ("); - buffer.append(exceptionType.getCanonicalText()); - buffer.append(" ").append(exceptionName).append("){}"); - String catchSectionText = buffer.toString(); - final FileElement holderElement = DummyHolderFactory.createHolder(myManager, context).getTreeElement(); - TreeElement catchSection = getJavaParsingContext(holderElement).getStatementParsing().parseCatchSectionText(catchSectionText); - if (catchSection == null || catchSection.getElementType() != JavaElementType.CATCH_SECTION) { - LOG.error(catchSectionText + "\nPSI:" + (catchSection == null ? null : DebugUtil.treeToString(catchSection, false))); + public PsiCatchSection createCatchSection(@NotNull final PsiClassType exceptionType, @NotNull final String exceptionName, + final PsiElement context) throws IncorrectOperationException { + final String text = join("catch (", exceptionType.getCanonicalText(), " ", exceptionName, ") {}"); + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, CATCH_SECTION, false), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiCatchSection)) { + throw new IncorrectOperationException("Incorrect catch section \"" + text + "\"."); } - holderElement.rawAddChildren(catchSection); - PsiCatchSection psiCatchSection = (PsiCatchSection)SourceTreeToPsiMap.treeElementToPsi(catchSection); - - setupCatchBlock(exceptionName, context, psiCatchSection); - return (PsiCatchSection)myManager.getCodeStyleManager().reformat(psiCatchSection); + setupCatchBlock(exceptionName, context, (PsiCatchSection)element); + return (PsiCatchSection)myManager.getCodeStyleManager().reformat(element); } - private void setupCatchBlock(String exceptionName, PsiElement context, PsiCatchSection psiCatchSection) - throws IncorrectOperationException { - FileTemplate catchBodyTemplate = FileTemplateManager.getInstance().getCodeTemplate(JavaTemplateUtil.TEMPLATE_CATCH_BODY); + private void setupCatchBlock(final String exceptionName, final PsiElement context, final PsiCatchSection psiCatchSection) + throws IncorrectOperationException { + final FileTemplate catchBodyTemplate = FileTemplateManager.getInstance().getCodeTemplate(JavaTemplateUtil.TEMPLATE_CATCH_BODY); LOG.assertTrue(catchBodyTemplate != null); - Properties props = new Properties(); + final Properties props = new Properties(); props.setProperty(FileTemplate.ATTRIBUTE_EXCEPTION, exceptionName); if (context != null && context.isPhysical()) { - PsiDirectory directory = context.getContainingFile().getContainingDirectory(); + final PsiDirectory directory = context.getContainingFile().getContainingDirectory(); if (directory != null) { JavaTemplateUtil.setPackageNameAttribute(props, directory); } } - PsiCodeBlock codeBlockFromText; + + final PsiCodeBlock codeBlockFromText; try { - String catchBody = catchBodyTemplate.getText(props); - codeBlockFromText = createCodeBlockFromText("{\n" + catchBody + "\n}", null); + codeBlockFromText = createCodeBlockFromText("{\n" + catchBodyTemplate.getText(props) + "\n}", null); } catch (ProcessCanceledException ce) { throw ce; } catch (Exception e) { - throw new IncorrectOperationException("Incorrect file template",e); + throw new IncorrectOperationException("Incorrect file template", e); } psiCatchSection.getCatchBlock().replace(codeBlockFromText); } - public PsiType createPrimitiveType(@NotNull String text, @NotNull PsiAnnotation[] annotations) { - if (annotations.length == 0) { - return PsiElementFactoryImpl.getPrimitiveType(text);//todo + public PsiType createPrimitiveType(@NotNull final String text, @NotNull final PsiAnnotation[] annotations) throws IncorrectOperationException { + final PsiPrimitiveType primitiveType = getPrimitiveType(text); + if (primitiveType == null) { + throw new IncorrectOperationException("Incorrect primitive type \"" + text + "\"."); } - return new PsiPrimitiveType(text, annotations); + return annotations.length == 0 ? primitiveType : new PsiPrimitiveType(text, annotations); + } + + public static PsiPrimitiveType getPrimitiveType(final String text) { + return PRIMITIVE_TYPES.get(text); } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/JavaDummyElement.java b/java/java-impl/src/com/intellij/psi/impl/source/JavaDummyElement.java new file mode 100644 index 000000000000..c54c4e18eba8 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/source/JavaDummyElement.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2010 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.psi.impl.source; + +import com.intellij.lang.java.parser.JavaParserUtil; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.impl.source.tree.FileElement; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.impl.source.tree.TreeElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Dummy file element for using together with DummyHolder. + * See {@link com.intellij.psi.impl.PsiJavaParserFacadeImpl} for details. + */ +public class JavaDummyElement extends FileElement { + @NotNull private final JavaParserUtil.ParserWrapper myParser; + private final boolean myConsumeAll; + @NotNull private final LanguageLevel myLanguageLevel; + + public JavaDummyElement(@Nullable final CharSequence text, @NotNull final JavaParserUtil.ParserWrapper parser, final boolean consumeAll) { + this(text, parser, consumeAll, LanguageLevel.HIGHEST); + } + + public JavaDummyElement(@Nullable final CharSequence text, + @NotNull final JavaParserUtil.ParserWrapper parser, + final boolean consumeAll, + @NotNull final LanguageLevel level) { + super(JavaElementType.DUMMY_ELEMENT, text); + myParser = parser; + myConsumeAll = consumeAll; + myLanguageLevel = level; + } + + @NotNull + public JavaParserUtil.ParserWrapper getParser() { + return myParser; + } + + public boolean consumeAll() { + return myConsumeAll; + } + + @NotNull + public LanguageLevel getLanguageLevel() { + return myLanguageLevel; + } + + @Override + public TreeElement getFirstChildNode() { + try { + return super.getFirstChildNode(); + } + catch (AssertionError e) { + return null; // masquerade parser errors + } + } + + @Override + public TreeElement getLastChildNode() { + try { + return super.getLastChildNode(); + } + catch (AssertionError e) { + return null; // masquerade parser errors + } + } +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/ClassBodyParsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/ClassBodyParsing.java index af3dcdf38783..5261951b12a6 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/ClassBodyParsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/ClassBodyParsing.java @@ -25,7 +25,7 @@ import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.tree.IElementType; /** - * + * @deprecated old Java parser is deprecated in favor of PSI builder-based one (see com.intellij.lang.java.parser.*) (to remove in IDEA 11). */ public class ClassBodyParsing extends Parsing { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.parsing.ClassBodyParsing"); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java index a220b14d694a..10899f2551ef 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/DeclarationParsing.java @@ -32,7 +32,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * + * @deprecated old Java parser is deprecated in favor of PSI builder-based one (see com.intellij.lang.java.parser.*) (to remove in IDEA 11). */ public class DeclarationParsing extends Parsing { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.parsing.DeclarationParsing"); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/ExpressionParsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/ExpressionParsing.java index fc27fc95ca14..fb96293d27e0 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/ExpressionParsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/ExpressionParsing.java @@ -34,6 +34,9 @@ import com.intellij.psi.tree.TokenSet; import com.intellij.util.CharTable; import org.jetbrains.annotations.NotNull; +/** + * @deprecated old Java parser is deprecated in favor of PSI builder-based one (see com.intellij.lang.java.parser.*) (to remove in IDEA 11). + */ public class ExpressionParsing extends Parsing { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.parsing.ExpressionParsing"); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/FileTextParsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/FileTextParsing.java index 50bdf945ddd0..93035892410e 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/FileTextParsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/FileTextParsing.java @@ -31,7 +31,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * + * @deprecated old Java parser is deprecated in favor of PSI builder-based one (see com.intellij.lang.java.parser.*) (to remove in IDEA 11). */ public class FileTextParsing extends Parsing { public FileTextParsing(JavaParsingContext context) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/ImportsTextParsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/ImportsTextParsing.java index 2a24d49bd43a..bae311297dba 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/ImportsTextParsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/ImportsTextParsing.java @@ -28,7 +28,7 @@ import com.intellij.psi.TokenType; import org.jetbrains.annotations.Nullable; /** - * + * @deprecated old Java parser is deprecated in favor of PSI builder-based one (see com.intellij.lang.java.parser.*) (to remove in IDEA 11). */ public class ImportsTextParsing extends Parsing { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.parsing.ImportsTextParsing"); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/JavadocParsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/JavadocParsing.java index 0617588c385b..b43a2b70755d 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/JavadocParsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/JavadocParsing.java @@ -33,6 +33,9 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NonNls; +/** + * todo[r.sh] rewrite and deprecate + */ public class JavadocParsing extends Parsing { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.parsing.JavadocParsing"); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/Parsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/Parsing.java index b9a38cba114a..a93645b172a5 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/Parsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/Parsing.java @@ -33,6 +33,9 @@ import com.intellij.util.CharTable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * @deprecated old Java parser is deprecated in favor of PSI builder-based one (see com.intellij.lang.java.parser.*) (to remove in IDEA 11). + */ public class Parsing { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.parsing.Parsing"); protected static final boolean DEEP_PARSE_BLOCKS_IN_STATEMENTS = false; @@ -198,8 +201,8 @@ public class Parsing { return type; } - public CompositeElement parseTypeWithEllipsis(Lexer lexer, boolean eatLastDot, boolean allowWilcard) { - CompositeElement type = parseType(lexer, eatLastDot, allowWilcard, false); + public CompositeElement parseTypeWithEllipsis(Lexer lexer, boolean eatLastDot, boolean allowWildcard) { + CompositeElement type = parseType(lexer, eatLastDot, allowWildcard, false); if (type == null) return null; if (lexer.getTokenType() == JavaTokenType.ELLIPSIS) { CompositeElement type1 = ASTFactory.composite(JavaElementType.TYPE); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/StatementParsing.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/StatementParsing.java index 6e4f8feade39..c45036a40403 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/StatementParsing.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/StatementParsing.java @@ -33,6 +33,9 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +/** + * @deprecated old Java parser is deprecated in favor of PSI builder-based one (see com.intellij.lang.java.parser.*) (to remove in IDEA 11). + */ public class StatementParsing extends Parsing { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.parsing.StatementParsing"); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/PsiDocTagValueManipulator.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/PsiDocTagValueManipulator.java index 66fd5a77ae72..4388efd53c9c 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/PsiDocTagValueManipulator.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/PsiDocTagValueManipulator.java @@ -36,7 +36,7 @@ public class PsiDocTagValueManipulator extends AbstractElementManipulator parseContents(final LighterLazyParseableNode chameleon) { final PsiBuilder builder = JavaParserUtil.createBuilder(chameleon); StatementParser.parseCodeBlockDeep(builder, true); @@ -194,6 +198,8 @@ public interface JavaElementType { ILazyParseableElementType CODE_BLOCK = JavaParserDefinition.USE_NEW_PARSER ? new ICodeBlockNewElementType() : new ICodeBlockElementType(); IElementType STATEMENTS = new ICodeFragmentElementType("STATEMENTS", StdLanguages.JAVA) { + @Nullable + @Override public ASTNode parseContents(final ASTNode chameleon) { if (JavaParserDefinition.USE_NEW_PARSER) { return JavaParserUtil.parseFragment(chameleon, @@ -213,6 +219,8 @@ public interface JavaElementType { }; IElementType EXPRESSION_TEXT = new ICodeFragmentElementType("EXPRESSION_TEXT", StdLanguages.JAVA) { + @Nullable + @Override public ASTNode parseContents(final ASTNode chameleon) { if (JavaParserDefinition.USE_NEW_PARSER) { return JavaParserUtil.parseFragment(chameleon, @@ -231,6 +239,8 @@ public interface JavaElementType { }; IElementType REFERENCE_TEXT = new ICodeFragmentElementType("REFERENCE_TEXT", StdLanguages.JAVA) { + @Nullable + @Override public ASTNode parseContents(final ASTNode chameleon) { if (JavaParserDefinition.USE_NEW_PARSER) { return JavaParserUtil.parseFragment(chameleon, @@ -248,6 +258,8 @@ public interface JavaElementType { }; IElementType TYPE_TEXT = new ICodeFragmentElementType("TYPE_TEXT", StdLanguages.JAVA) { + @Nullable + @Override public ASTNode parseContents(final ASTNode chameleon) { if (JavaParserDefinition.USE_NEW_PARSER) { return JavaParserUtil.parseFragment(chameleon, @@ -264,4 +276,14 @@ public interface JavaElementType { SharedImplUtil.findCharTableByTree(chameleon)); } }; + + IElementType DUMMY_ELEMENT = new ILazyParseableElementType("DUMMY_ELEMENT", StdLanguages.JAVA) { + @Nullable + @Override + public ASTNode parseContents(final ASTNode chameleon) { + assert chameleon instanceof JavaDummyElement : chameleon; + final JavaDummyElement dummyElement = (JavaDummyElement)chameleon; + return JavaParserUtil.parseFragment(chameleon, dummyElement.getParser(), dummyElement.consumeAll(), dummyElement.getLanguageLevel()); + } + }; } diff --git a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java index f834fb0292b4..19f0c1df49c4 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java @@ -395,7 +395,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor { final CodeStyleManager codeStyleManager = manager.getCodeStyleManager(); @NonNls final StringBuilder fieldBuffer = new StringBuilder(); final String delegateVisibility = calculateDelegateVisibility(); - fieldBuffer.append(delegateVisibility).append(' '); + if (delegateVisibility.length() > 0) fieldBuffer.append(delegateVisibility).append(' '); fieldBuffer.append("final "); final String fullyQualifiedName = StringUtil.getQualifiedName(newPackageName, newClassName); fieldBuffer.append(fullyQualifiedName); @@ -408,8 +408,7 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor { } fieldBuffer.append(' '); fieldBuffer.append(delegateFieldName); - fieldBuffer.append('='); - fieldBuffer.append("new ").append(fullyQualifiedName); + fieldBuffer.append(" = new ").append(fullyQualifiedName); if (!typeParams.isEmpty()) { fieldBuffer.append('<'); for (PsiTypeParameter typeParameter : typeParams) { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java index 2b5749a0eef2..ca4042a25a18 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java @@ -312,8 +312,7 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP } if (compatibleParamObjectConstructor != null) { - PsiDocComment psiDocComment = - JavaPsiFacade.getElementFactory(myProject).createDocCommentFromText("/**\n*/", compatibleParamObjectConstructor); + PsiDocComment psiDocComment = JavaPsiFacade.getElementFactory(myProject).createDocCommentFromText("/**\n*/"); psiDocComment = (PsiDocComment)compatibleParamObjectConstructor.addBefore(psiDocComment, compatibleParamObjectConstructor.getFirstChild()); for (PsiDocTag tag : mergedTags) { diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringHierarchyUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringHierarchyUtil.java index 573eeffbc369..257f978adc0a 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringHierarchyUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringHierarchyUtil.java @@ -38,7 +38,8 @@ import java.util.*; public class RefactoringHierarchyUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.util.RefactoringHierarchyUtil"); - private static final List PRIMITIVE_TYPES = Arrays.asList( + + private static final List PRIMITIVE_TYPES = Arrays.asList( PsiType.BYTE, PsiType.CHAR, PsiType.SHORT, PsiType.INT, PsiType.LONG, PsiType.FLOAT, PsiType.DOUBLE ); diff --git a/java/java-impl/src/com/intellij/util/xml/PsiClassConverter.java b/java/java-impl/src/com/intellij/util/xml/PsiClassConverter.java index df16f85a8abd..32785e7a44c3 100644 --- a/java/java-impl/src/com/intellij/util/xml/PsiClassConverter.java +++ b/java/java-impl/src/com/intellij/util/xml/PsiClassConverter.java @@ -97,7 +97,7 @@ public class PsiClassConverter extends Converter implements CustomRefe @Nullable protected GlobalSearchScope getScope(final GenericDomValue domValue) { final Module module = domValue.getModule(); - return module == null ? null : GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module); + return module == null ? null : GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false); } public static class AnnotationType extends PsiClassConverter { diff --git a/java/java-tests/testData/codeInsight/completion/normal/MethodWithLeftParTailType2_after.java b/java/java-tests/testData/codeInsight/completion/normal/MethodWithLeftParTailType2_after.java index 82b0a037822d..b4b5c16848e6 100644 --- a/java/java-tests/testData/codeInsight/completion/normal/MethodWithLeftParTailType2_after.java +++ b/java/java-tests/testData/codeInsight/completion/normal/MethodWithLeftParTailType2_after.java @@ -3,6 +3,6 @@ class MyClass { void foo(int a) {} { - foo() + foo(); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/ConstructorNoPairBracketSemicolon-out.java b/java/java-tests/testData/codeInsight/completion/smartType/ConstructorNoPairBracketSemicolon-out.java new file mode 100644 index 000000000000..b1b9a92a066c --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/ConstructorNoPairBracketSemicolon-out.java @@ -0,0 +1,5 @@ +class A { + { + String c = new String(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/ConstructorNoPairBracketSemicolon.java b/java/java-tests/testData/codeInsight/completion/smartType/ConstructorNoPairBracketSemicolon.java new file mode 100644 index 000000000000..f05c0210cb13 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/ConstructorNoPairBracketSemicolon.java @@ -0,0 +1,5 @@ +class A { + { + String c = new Stri + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/MethodNoPairBracketComma-out.java b/java/java-tests/testData/codeInsight/completion/smartType/MethodNoPairBracketComma-out.java new file mode 100644 index 000000000000..883ef9b8a8f8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/MethodNoPairBracketComma-out.java @@ -0,0 +1,8 @@ +class A { + void foo(String bar, int a) {} + String zoo(int b) {} + + { + foo(zoo(), ) + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/MethodNoPairBracketComma.java b/java/java-tests/testData/codeInsight/completion/smartType/MethodNoPairBracketComma.java new file mode 100644 index 000000000000..ab1e7d370306 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/MethodNoPairBracketComma.java @@ -0,0 +1,8 @@ +class A { + void foo(String bar, int a) {} + String zoo(int b) {} + + { + foo(zo) + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index d00328d0b1b7..156c4d9f8b4f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -477,28 +477,26 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { public void testSameNamedFieldAndLocal() throws Throwable { doTest(); } - public void testNoTailWhenNoPairBracket() throws Throwable { - doTestNoPairBracket(); - } + public void testNoTailWhenNoPairBracket() throws Throwable { doTestNoPairBracket(Lookup.NORMAL_SELECT_CHAR); } - public void testNoTailWhenNoPairBracket2() throws Throwable { - doTestNoPairBracket(); - } + public void testNoTailWhenNoPairBracket2() throws Throwable { doTestNoPairBracket(Lookup.NORMAL_SELECT_CHAR); } - private void doTestNoPairBracket() throws Exception { + private void doTestNoPairBracket(final char c) throws Exception { boolean old = CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET; CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET = false; try { - doTest(); + doTest(c); } finally { CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET = old; } } - public void testNoConstructorTailWhenNoPairBracket() throws Throwable { - doTestNoPairBracket(); - } + public void testNoConstructorTailWhenNoPairBracket() throws Throwable { doTestNoPairBracket(Lookup.NORMAL_SELECT_CHAR); } + + public void testConstructorNoPairBracketSemicolon() throws Throwable { doTestNoPairBracket(';'); } + + public void testMethodNoPairBracketComma() throws Throwable { doTestNoPairBracket(','); } public void testAbstractClassTwice() throws Throwable { configureByTestName(); diff --git a/java/openapi/src/com/intellij/psi/PsiElementFactory.java b/java/openapi/src/com/intellij/psi/PsiElementFactory.java index 0ac50882572e..d74a242b882b 100644 --- a/java/openapi/src/com/intellij/psi/PsiElementFactory.java +++ b/java/openapi/src/com/intellij/psi/PsiElementFactory.java @@ -58,8 +58,7 @@ public interface PsiElementFactory extends PsiJavaParserFacade { * @return the created enum instance. * @throws IncorrectOperationException if name is not a valid Java identifier. */ - - PsiClass createEnum(@NotNull @NonNls String name) throws IncorrectOperationException; + @NotNull PsiClass createEnum(@NotNull @NonNls String name) throws IncorrectOperationException; /** * Creates a field with the specified name and type. @@ -158,7 +157,7 @@ public interface PsiElementFactory extends PsiJavaParserFacade { * * @param type the type to detach. * @return the detached type. - * @deprecated Optimization method, do not use if you do not understand what it does. + * @deprecated does nothing (remove in IDEA 11) */ @NotNull PsiType detachType(@NotNull PsiType type); @@ -189,9 +188,10 @@ public interface PsiElementFactory extends PsiJavaParserFacade { @Nullable PsiPrimitiveType createPrimitiveType(@NotNull String text); /** - * The same as {@link #createTypeByFQClassName(String, GlobalSearchScope)} with {@link GlobalSearchScope#allScope()} + * The same as {@link #createTypeByFQClassName(String, GlobalSearchScope)} + * with {@link GlobalSearchScope#allScope(com.intellij.openapi.project.Project)}. * - * @param qName the full-qualified name of the class to create the reference to. + * @param qName the full-qualified name of the class to create the reference to. * @return the class type instance. */ @NotNull PsiClassType createTypeByFQClassName(@NotNull @NonNls String qName); @@ -419,6 +419,7 @@ public interface PsiElementFactory extends PsiJavaParserFacade { /** * Returns a synthetic Java class containing methods which are defined on Java arrays. * + * @param languageLevel language level used to construct array class. * @return the array synthetic class. */ @NotNull PsiClass getArrayClass(@NotNull LanguageLevel languageLevel); @@ -428,7 +429,7 @@ public interface PsiElementFactory extends PsiJavaParserFacade { * are defined on Java arrays with the specified element type. * * @param componentType the component type of the array for which the class type is returned. - * @param languageLevel + * @param languageLevel language level used to construct array class. * @return the class type the array synthetic class. */ @NotNull PsiClassType getArrayClassType(@NotNull PsiType componentType, @NotNull final LanguageLevel languageLevel); diff --git a/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java b/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java index a52c7e26dc0f..676de126bfba 100644 --- a/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java +++ b/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java @@ -14,9 +14,6 @@ * limitations under the License. */ -/* - * @author max - */ package com.intellij.psi; import com.intellij.pom.java.LanguageLevel; @@ -26,28 +23,41 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +/* + * @author max + */ public interface PsiJavaParserFacade extends PsiParserFacade { /** * Creates a JavaDoc tag from the specified text. * * @param docTagText the text of the JavaDoc tag. - * @param context ignored; no longer used * @return the created tag. * @throws com.intellij.util.IncorrectOperationException if the text of the tag is not valid. */ @NotNull - PsiDocTag createDocTagFromText(@NotNull String docTagText, @Deprecated PsiElement context) throws IncorrectOperationException; + PsiDocTag createDocTagFromText(@NotNull String docTagText) throws IncorrectOperationException; + + /** + * @deprecated use {@link #createDocTagFromText(String)} (to remove in IDEA 11) + */ + @NotNull + PsiDocTag createDocTagFromText(@NotNull String docTagText, PsiElement context) throws IncorrectOperationException; /** * Creates a JavaDoc comment from the specified text. * * @param docCommentText the text of the JavaDoc comment. - * @param context ignored; no longer used * @return the created comment. * @throws com.intellij.util.IncorrectOperationException if the text of the comment is not valid. */ @NotNull - PsiDocComment createDocCommentFromText(@NotNull String docCommentText, @Deprecated PsiElement context) throws IncorrectOperationException; + PsiDocComment createDocCommentFromText(@NotNull String docCommentText) throws IncorrectOperationException; + + /** + * @deprecated use {@link #createDocCommentFromText(String)} (to remove in IDEA 11) + */ + @NotNull + PsiDocComment createDocCommentFromText(@NotNull String docCommentText, PsiElement context) throws IncorrectOperationException; /** * Creates a Java class from the specified text. @@ -110,7 +120,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * Creates a Java type from the specified text. * * @param text the text of the type to create (for example, a primitive type keyword, an array - * declaration or the name of a class) + * declaration or the name of a class). * @param context the PSI element used as context for resolving the reference. * @return the created type instance. * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid type. @@ -193,7 +203,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * type and name. * * @param exceptionType the type of the exception to catch. - * @param exceptionName the name of the variable in which the caught exception is stored (may be an empty string) + * @param exceptionName the name of the variable in which the caught exception is stored (may be an empty string). * @param context the context for resolving references. * @return the created catch section instance. * @throws IncorrectOperationException if some of the parameters are not valid. @@ -201,5 +211,13 @@ public interface PsiJavaParserFacade extends PsiParserFacade { @NotNull PsiCatchSection createCatchSection(@NotNull PsiClassType exceptionType, @NotNull String exceptionName, PsiElement context) throws IncorrectOperationException; - PsiType createPrimitiveType(@NotNull String text, @NotNull PsiAnnotation[] annotations); + /** + * Creates a Java type from the specified text. + * + * @param text the text of the type to create (a primitive type keyword). + * @param annotations array (possible empty) of annotations to annotate the created type. + * @return the created type instance. + * @throws IncorrectOperationException if some of the parameters are not valid. + */ + PsiType createPrimitiveType(@NotNull String text, @NotNull PsiAnnotation[] annotations) throws IncorrectOperationException; } diff --git a/java/openapi/src/com/intellij/psi/PsiType.java b/java/openapi/src/com/intellij/psi/PsiType.java index 7d62a6f7ca91..5c70c8a21576 100644 --- a/java/openapi/src/com/intellij/psi/PsiType.java +++ b/java/openapi/src/com/intellij/psi/PsiType.java @@ -27,16 +27,17 @@ import org.jetbrains.annotations.Nullable; * Representation of Java type (primitive type, array or class type). */ public abstract class PsiType implements PsiAnnotationOwner { - public static final PsiType BYTE = new PsiPrimitiveType("byte", "java.lang.Byte"); - public static final PsiType CHAR = new PsiPrimitiveType("char", "java.lang.Character"); - public static final PsiType DOUBLE = new PsiPrimitiveType("double", "java.lang.Double"); - public static final PsiType FLOAT = new PsiPrimitiveType("float", "java.lang.Float"); - public static final PsiType INT = new PsiPrimitiveType("int", "java.lang.Integer"); - public static final PsiType LONG = new PsiPrimitiveType("long", "java.lang.Long"); - public static final PsiType SHORT = new PsiPrimitiveType("short", "java.lang.Short"); - public static final PsiType BOOLEAN = new PsiPrimitiveType("boolean", "java.lang.Boolean"); - public static final PsiType VOID = new PsiPrimitiveType("void", "java.lang.Void"); - public static final PsiType NULL = new PsiPrimitiveType("null", (String)null); + public static final PsiPrimitiveType BYTE = new PsiPrimitiveType("byte", "java.lang.Byte"); + public static final PsiPrimitiveType CHAR = new PsiPrimitiveType("char", "java.lang.Character"); + public static final PsiPrimitiveType DOUBLE = new PsiPrimitiveType("double", "java.lang.Double"); + public static final PsiPrimitiveType FLOAT = new PsiPrimitiveType("float", "java.lang.Float"); + public static final PsiPrimitiveType INT = new PsiPrimitiveType("int", "java.lang.Integer"); + public static final PsiPrimitiveType LONG = new PsiPrimitiveType("long", "java.lang.Long"); + public static final PsiPrimitiveType SHORT = new PsiPrimitiveType("short", "java.lang.Short"); + public static final PsiPrimitiveType BOOLEAN = new PsiPrimitiveType("boolean", "java.lang.Boolean"); + public static final PsiPrimitiveType VOID = new PsiPrimitiveType("void", "java.lang.Void"); + public static final PsiPrimitiveType NULL = new PsiPrimitiveType("null", (String)null); + public static final PsiType[] EMPTY_ARRAY = new PsiType[0]; private final PsiAnnotation[] myAnnotations; diff --git a/java/openapi/src/com/intellij/util/xml/DomJavaUtil.java b/java/openapi/src/com/intellij/util/xml/DomJavaUtil.java index 47171693c07d..c21fd2278d4f 100644 --- a/java/openapi/src/com/intellij/util/xml/DomJavaUtil.java +++ b/java/openapi/src/com/intellij/util/xml/DomJavaUtil.java @@ -41,7 +41,7 @@ public class DomJavaUtil { if (searchScope == null) { if (module != null) { - scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module); + scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false); } else { scope = file.getResolveScope(); diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java index 3b45c626de31..e60ee0a4902a 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java @@ -22,6 +22,7 @@ import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.IntentionManager; import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler; import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.InspectionToolProvider; @@ -33,13 +34,19 @@ import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; import com.intellij.codeInspection.ex.ToolsImpl; import com.intellij.ide.startup.StartupManagerEx; import com.intellij.ide.startup.impl.StartupManagerImpl; +import com.intellij.lang.ExternalAnnotatorsFilter; +import com.intellij.lang.LanguageAnnotators; +import com.intellij.lang.StdLanguages; import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; +import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.startup.StartupManager; @@ -57,15 +64,19 @@ import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; import com.intellij.psi.impl.JavaPsiFacadeEx; +import com.intellij.psi.impl.search.IndexPatternBuilder; +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.impl.source.tree.TreeUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.UsageSearchContext; +import com.intellij.psi.xml.XmlFileNSInfoProvider; import com.intellij.testFramework.ExpectedHighlightingData; import com.intellij.testFramework.FileTreeAccessFilter; import com.intellij.testFramework.LightPlatformTestCase; import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl; import com.intellij.util.IncorrectOperationException; +import com.intellij.xml.XmlSchemaProvider; import gnu.trove.THashMap; import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NonNls; @@ -160,6 +171,21 @@ public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase { DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(false); myRunCommandForTest = !annotatedWith(DoNotWrapInCommand.class); + + if (isPerformanceTest()) { + IntentionManager.getInstance().getAvailableIntentionActions(); // hack to avoid slowdowns in PyExtensionFactory + PathManagerEx.getTestDataPath(); // to cache stuff + ReferenceProvidersRegistry.getInstance(getProject()); // preload tons of classes + InjectedLanguageManager.getInstance(getProject()); // zillion of Dom Sem classes + LanguageAnnotators.INSTANCE.allForLanguage(StdLanguages.JAVA); // pile of annotator classes loads + LanguageAnnotators.INSTANCE.allForLanguage(StdLanguages.XML); + ProblemHighlightFilter.EP_NAME.getExtensions(); + Extensions.getExtensions(ImplicitUsageProvider.EP_NAME); + Extensions.getExtensions(XmlSchemaProvider.EP_NAME); + Extensions.getExtensions(XmlFileNSInfoProvider.EP_NAME); + Extensions.getExtensions(ExternalAnnotatorsFilter.EXTENSION_POINT_NAME); + Extensions.getExtensions(IndexPatternBuilder.EP_NAME); + } } @Override diff --git a/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementBuilder.java b/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementBuilder.java index f49c58ced67c..14fa3f686dc3 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementBuilder.java +++ b/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementBuilder.java @@ -235,6 +235,11 @@ public class LookupElementBuilder extends LookupElement { return true; } + @Override + public String toString() { + return "LookupElementBuilder: string=" + getLookupString() + "; handler=" + myInsertHandler; + } + @Override public int hashCode() { int result = 0; diff --git a/platform/lang-api/src/com/intellij/facet/frameworks/LibrariesDownloadAssistant.java b/platform/lang-api/src/com/intellij/facet/frameworks/LibrariesDownloadAssistant.java index 5d1676e0e255..61340ad030c0 100644 --- a/platform/lang-api/src/com/intellij/facet/frameworks/LibrariesDownloadAssistant.java +++ b/platform/lang-api/src/com/intellij/facet/frameworks/LibrariesDownloadAssistant.java @@ -11,6 +11,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; +import com.intellij.util.net.HttpConfigurable; import com.intellij.util.xmlb.XmlSerializationException; import com.intellij.util.xmlb.XmlSerializer; import org.jetbrains.annotations.NotNull; @@ -46,11 +47,17 @@ public class LibrariesDownloadAssistant { final String serviceUrl = LibrariesDownloadConnectionService.getInstance().getServiceUrl(); if (StringUtil.isNotEmpty(serviceUrl)) { try { - return new URL(serviceUrl + "/" + id + "/"); + final String url = serviceUrl + "/" + id + "/"; + HttpConfigurable.getInstance().prepareURL(url); + + return new URL(url); } catch (MalformedURLException e) { LOG.error(e); } + catch (IOException e) { + LOG.error(e); + } } return null; diff --git a/platform/lang-api/src/com/intellij/facet/frameworks/ui/LibrariesDownloadUiUtil.java b/platform/lang-api/src/com/intellij/facet/frameworks/ui/LibrariesDownloadUiUtil.java new file mode 100644 index 000000000000..1dc9652b80d3 --- /dev/null +++ b/platform/lang-api/src/com/intellij/facet/frameworks/ui/LibrariesDownloadUiUtil.java @@ -0,0 +1,95 @@ +/* + * Copyright 2000-2010 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.facet.frameworks.ui; + +import com.intellij.facet.frameworks.LibrariesDownloadAssistant; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.ui.CollectionComboBoxModel; +import com.intellij.util.ui.update.Activatable; +import com.intellij.util.ui.update.UiNotifyConnector; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LibrariesDownloadUiUtil { + + private LibrariesDownloadUiUtil() { + } + + public static JComboBox createVersionsCombobox(@NotNull final String groupId, final URL... localUrls) { + final JComboBox jComboBox = new JComboBox(); + + initAsyncComboBoxModel(jComboBox, groupId, localUrls); + + return jComboBox; + } + + public static void initAsyncComboBoxModel(@NotNull final JComboBox jComboBox, + @NotNull final String groupId, + final URL... localUrls) { + final List items = new ArrayList(); + + new UiNotifyConnector.Once(jComboBox, new Activatable() { + @Override + public void showNotify() { + loadItems(jComboBox, items, groupId, localUrls); + } + + @Override + public void hideNotify() { + } + }); + + items.add("loading..."); + jComboBox.setModel(new CollectionComboBoxModel(items, items.get(0))); + jComboBox.setEnabled(false); + } + + private static void loadItems(@NotNull final JComboBox jComboBox, + final List items, + final String groupId, + final URL... localUrls) { + final ModalityState state = ModalityState.current(); + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + final List newItems = new ArrayList(); + newItems.addAll(Arrays.asList(LibrariesDownloadAssistant.getVersions(groupId, localUrls))); + + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + items.clear(); + if (!newItems.isEmpty()) { + items.addAll(newItems); + final CollectionComboBoxModel model = (CollectionComboBoxModel)jComboBox.getModel(); + model.update(); + jComboBox.setSelectedIndex(0); + } + jComboBox.setEnabled(true); + } + }, state); + } + } + + ); + } +} diff --git a/platform/lang-api/src/com/intellij/lang/folding/FoldingDescriptor.java b/platform/lang-api/src/com/intellij/lang/folding/FoldingDescriptor.java index 47593ec2449f..5833f4621267 100644 --- a/platform/lang-api/src/com/intellij/lang/folding/FoldingDescriptor.java +++ b/platform/lang-api/src/com/intellij/lang/folding/FoldingDescriptor.java @@ -41,6 +41,7 @@ public class FoldingDescriptor { private final TextRange myRange; @Nullable private final FoldingGroup myGroup; private Set myDependencies; + private final boolean myNeverExpands; /** * Creates a folding region related to the specified AST node and covering the specified @@ -66,14 +67,33 @@ public class FoldingDescriptor { * Creates a folding region related to the specified AST node and covering the specified * text range. * @param node The node to which the folding region is related. The node is then passed to - * {@link FoldingBuilder#getPlaceholderText(com.intellij.lang.ASTNode)} and - * {@link FoldingBuilder#isCollapsedByDefault(com.intellij.lang.ASTNode)}. + * {@link com.intellij.lang.folding.FoldingBuilder#getPlaceholderText(com.intellij.lang.ASTNode)} and + * {@link com.intellij.lang.folding.FoldingBuilder#isCollapsedByDefault(com.intellij.lang.ASTNode)}. * @param range The folded text range. * @param group Regions with the same group instance expand and collapse together. * @param dependencies folding dependencies: other files or elements that could change * folding description */ public FoldingDescriptor(@NotNull ASTNode node, @NotNull TextRange range, @Nullable FoldingGroup group, Set dependencies) { + this(node, range, group, dependencies, false); + } + + /** + * Creates a folding region related to the specified AST node and covering the specified + * text range. + * @param node The node to which the folding region is related. The node is then passed to + * {@link com.intellij.lang.folding.FoldingBuilder#getPlaceholderText(com.intellij.lang.ASTNode)} and + * {@link com.intellij.lang.folding.FoldingBuilder#isCollapsedByDefault(com.intellij.lang.ASTNode)}. + * @param range The folded text range. + * @param group Regions with the same group instance expand and collapse together. + * @param dependencies folding dependencies: other files or elements that could change + * @param neverExpands shall be true for fold regions that must not be ever expanded. + */ + public FoldingDescriptor(@NotNull ASTNode node, + @NotNull TextRange range, + @Nullable FoldingGroup group, + Set dependencies, + boolean neverExpands) { assert range.getStartOffset() + 1 < range.getEndOffset() : range; myElement = node; ProperTextRange.assertProperRange(range); @@ -81,6 +101,7 @@ public class FoldingDescriptor { myGroup = group; assert getRange().getLength() >= 2 : "range:" + getRange(); myDependencies = dependencies; + myNeverExpands = neverExpands; } /** @@ -122,4 +143,8 @@ public class FoldingDescriptor { public Set getDependencies() { return myDependencies; } + + public boolean isNonExpandable() { + return myNeverExpands; + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/InitialConfigurationDialog.form b/platform/lang-impl/src/com/intellij/application/options/InitialConfigurationDialog.form new file mode 100644 index 000000000000..55892db1d279 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/InitialConfigurationDialog.form @@ -0,0 +1,70 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/platform/lang-impl/src/com/intellij/application/options/InitialConfigurationDialog.java b/platform/lang-impl/src/com/intellij/application/options/InitialConfigurationDialog.java new file mode 100644 index 000000000000..5b4122ff63c1 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/InitialConfigurationDialog.java @@ -0,0 +1,172 @@ +package com.intellij.application.options; + +import com.intellij.application.options.colors.ColorAndFontOptions; +import com.intellij.application.options.colors.NewColorAndFontPanel; +import com.intellij.application.options.colors.SimpleEditorPreview; +import com.intellij.ide.todo.TodoConfiguration; +import com.intellij.ide.ui.ListCellRendererWrapper; +import com.intellij.openapi.application.ApplicationNamesInfo; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.keymap.Keymap; +import com.intellij.openapi.keymap.KeymapManager; +import com.intellij.openapi.keymap.impl.KeymapManagerImpl; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.SystemInfo; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +/** + * @author yole + */ +public class InitialConfigurationDialog extends DialogWrapper { + private JPanel myMainPanel; + private JComboBox myKeymapComboBox; + private JComboBox myColorSchemeComboBox; + private JButton myPreviewButton; + private String myColorSettingsPage; + + public InitialConfigurationDialog(Component parent, String colorSettingsPage) { + super(parent, true); + myColorSettingsPage = colorSettingsPage; + setTitle(ApplicationNamesInfo.getInstance().getFullProductName() + " Initial Configuration"); + + final ArrayList keymaps = new ArrayList(); + for (Keymap keymap : ((KeymapManagerImpl)KeymapManager.getInstance()).getAllKeymaps()) { + if (matchesPlatform(keymap)) { + keymaps.add(keymap); + } + } + + myKeymapComboBox.setModel(new DefaultComboBoxModel(keymaps.toArray(new Keymap[keymaps.size()]))); + myKeymapComboBox.setRenderer(new ListCellRendererWrapper(myKeymapComboBox.getRenderer()) { + @Override + public void customize(final JList list, final Object value, final int index, final boolean selected, final boolean cellHasFocus) { + Keymap keymap = (Keymap)value; + if (keymap == null) { + return; + } + if (KeymapManager.DEFAULT_IDEA_KEYMAP.equals(keymap.getName())) { + setText("IntelliJ IDEA Classic"); + } + else if ("Mac OS X".equals(keymap.getName())) { + setText("IntelliJ IDEA Classic - Mac OS X"); + } + else { + setText(keymap.getPresentableName()); + } + } + + }); + preselectKeyMap(keymaps); + + final EditorColorsScheme[] colorSchemes = EditorColorsManager.getInstance().getAllSchemes(); + myColorSchemeComboBox.setModel(new DefaultComboBoxModel(colorSchemes)); + myColorSchemeComboBox.setRenderer(new ListCellRendererWrapper(myColorSchemeComboBox.getRenderer()) { + @Override + public void customize(JList list, Object value, int index, boolean selected, boolean cellHasFocus) { + setText(((EditorColorsScheme)value).getName()); + } + + }); + + init(); + myPreviewButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + showColorSchemePreviewDialog(); + } + }); + } + + private void preselectKeyMap(ArrayList keymaps) { + if (SystemInfo.isMac) { + for (Keymap keymap : keymaps) { + if (keymap.getName().equals("Default for Mac OS X")) { + myKeymapComboBox.setSelectedItem(keymap); + break; + } + } + } + } + + private static boolean matchesPlatform(Keymap keymap) { + if (keymap.getName().equals(KeymapManager.DEFAULT_IDEA_KEYMAP)) { + return !SystemInfo.isMac; + } + else if (keymap.getName().equals(KeymapManager.MAC_OS_X_KEYMAP)) { + return SystemInfo.isMac; + } + else if (keymap.getName().equals("Default for GNOME") || keymap.getName().equals("Default for KDE") || + keymap.getName().equals("Default for XWin")) { + return SystemInfo.isLinux; + } + return true; + } + + private void showColorSchemePreviewDialog() { + showColorSchemePreviewDialog(ColorAndFontOptions.getColorAndFontsInstance()); + } + + private void showColorSchemePreviewDialog(final ColorAndFontOptions options) { + final NewColorAndFontPanel page = options.findPage(myColorSettingsPage); + assert page != null; + options.reset(); + final String selectedScheme = ((EditorColorsScheme)myColorSchemeComboBox.getSelectedItem()).getName(); + options.selectScheme(selectedScheme); + final SimpleEditorPreview preview = new SimpleEditorPreview(options, page.getSettingsPage()); + preview.updateView(); + DialogWrapper wrapper = new PreviewDialog(preview, selectedScheme); + wrapper.show(); + preview.disposeUIResources(); + options.disposeUIResources(); + } + + protected JComponent createCenterPanel() { + return myMainPanel; + } + + @Override + protected void doOKAction() { + super.doOKAction(); + // set keymap + ((KeymapManagerImpl)KeymapManager.getInstance()).setActiveKeymap((Keymap)myKeymapComboBox.getSelectedItem()); + // set color scheme + EditorColorsManager.getInstance().setGlobalScheme((EditorColorsScheme)myColorSchemeComboBox.getSelectedItem()); + // create default todo_pattern for color scheme + TodoConfiguration.getInstance().resetToDefaultTodoPatterns(); + } + + private class PreviewDialog extends DialogWrapper { + private final SimpleEditorPreview myPreview; + + public PreviewDialog(final SimpleEditorPreview preview, final String selectedScheme) { + super(myMainPanel, true); + myPreview = preview; + setTitle("Preview for " + selectedScheme); + init(); + } + + @Override + protected JComponent createCenterPanel() { + JPanel panel = new JPanel(new BorderLayout()) { + @Override + public Dimension getPreferredSize() { + return new Dimension(400, 300); + } + }; + panel.add(myPreview.getPanel(), BorderLayout.CENTER); + return panel; + } + + @Override + protected Action[] createActions() { + final Action action = getOKAction(); + action.putValue(Action.NAME, "Close"); + return new Action[]{action}; + } + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 6ea31eb29fba..5fdad4454373 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -34,6 +34,7 @@ import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.ex.ApplicationEx; +import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; @@ -157,7 +158,13 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { EditorUtil.fillVirtualSpaceUntilCaret(editor); documentManager.commitAllDocuments(); - assert editor.getDocument().getTextLength() == psiFile.getTextLength() : "unsuccessful commit"; + if (editor.getDocument().getTextLength() != psiFile.getTextLength()) { + if (ApplicationManagerEx.getApplicationEx().isInternal()) { + throw new AssertionError("unsuccessful commit: docText=" + editor.getDocument().getText() + "; fileText=" + psiFile.getText() + "; injected=" + (editor instanceof EditorWindow)); + } + + throw new AssertionError("unsuccessful commit: injected=" + (editor instanceof EditorWindow)); + } final Ref current = Ref.create(null); initializationContext[0] = new CompletionInitializationContext(editor, psiFile, myCompletionType) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/UnSelectWordHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/UnSelectWordHandler.java index 7627fcaf7e49..a56ea16499ad 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/UnSelectWordHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/UnSelectWordHandler.java @@ -67,7 +67,7 @@ public class UnSelectWordHandler extends EditorActionHandler { int caretOffset = editor.getCaretModel().getOffset(); - if (caretOffset > 0 && + if (caretOffset > 0 && caretOffset < text.length() && !Character.isJavaIdentifierPart(text.charAt(caretOffset)) && Character.isJavaIdentifierPart(text.charAt(caretOffset - 1))) { caretOffset--; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java index dd07ca494886..6189e527742c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java @@ -95,7 +95,10 @@ class UpdateFoldRegionsOperation implements Runnable { FoldingGroup group = descriptor.getGroup(); TextRange range = descriptor.getRange(); String placeholder = descriptor.getPlaceholderText(); - FoldRegion region = foldingModel.createFoldRegion(range.getStartOffset(), range.getEndOffset(), placeholder == null ? "..." : placeholder, group); + FoldRegion region = foldingModel.createFoldRegion(range.getStartOffset(), range.getEndOffset(), + placeholder == null ? "..." : placeholder, + group, + descriptor.isNonExpandable()); if (region == null) continue; if (!foldingModel.addFoldRegion(region)) { @@ -106,7 +109,7 @@ class UpdateFoldRegionsOperation implements Runnable { info.addRegion(region, smartPointerManager.createSmartPsiElementPointer(descriptor.getElement().getPsi())); newRegions.add(region); - boolean expandStatus = shouldExpandNewRegion(element, range, rangeToExpandStatusMap); + boolean expandStatus = !descriptor.isNonExpandable() && shouldExpandNewRegion(element, range, rangeToExpandStatusMap); if (group == null) { shouldExpand.put(region, expandStatus); } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index 0bc22bbeea7c..00ee4db4b203 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -1185,7 +1185,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo String commandLinePlaceholder = myCommandLineFolding.getPlaceholder(line); if (commandLinePlaceholder != null) { FoldRegion region = ((FoldingModelEx)myEditor.getFoldingModel()).createFoldRegion( - document.getLineStartOffset(line), document.getLineEndOffset(line), commandLinePlaceholder, null + document.getLineStartOffset(line), document.getLineEndOffset(line), commandLinePlaceholder, null, false ); toAdd.add(region); return; @@ -1218,7 +1218,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo int oEnd = CharArrayUtil.shiftBackward(chars, document.getLineEndOffset(lEnd) - 1, " \t") + 1; FoldRegion region = - ((FoldingModelEx)myEditor.getFoldingModel()).createFoldRegion(oStart, oEnd, prevFolding.getPlaceholderText(toFold), null); + ((FoldingModelEx)myEditor.getFoldingModel()).createFoldRegion(oStart, oEnd, prevFolding.getPlaceholderText(toFold), null, false); if (region != null) { toAdd.add(region); } diff --git a/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java b/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java index a0a56ba13ab2..55a430574e62 100644 --- a/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java +++ b/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java @@ -32,6 +32,7 @@ import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.InvalidDnDOperationException; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -89,9 +90,14 @@ public class PsiCopyPasteManager { Object transferData; try { transferData = content.getTransferData(ourDataFlavor); - } catch (UnsupportedFlavorException e) { + } + catch (UnsupportedFlavorException e) { return null; - } catch (IOException e) { + } + catch (IOException e) { + return null; + } + catch (InvalidDnDOperationException e) { return null; } diff --git a/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/EditLibraryDialog.form b/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/EditLibraryDialog.form index e58c238c7c25..e6ca688989ca 100644 --- a/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/EditLibraryDialog.form +++ b/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/EditLibraryDialog.form @@ -1,9 +1,9 @@
- - + + - + @@ -29,18 +29,19 @@ - + + - + - + @@ -52,7 +53,7 @@ - + @@ -72,7 +73,7 @@ - + @@ -83,6 +84,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/EditLibraryDialog.java b/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/EditLibraryDialog.java index 182a0561cc31..32cc32ee5981 100644 --- a/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/EditLibraryDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/EditLibraryDialog.java @@ -20,16 +20,21 @@ import com.intellij.ide.scriptingContext.LangScriptingContextProvider; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.ui.Util; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.libraries.scripting.ScriptingLibraryTable; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.components.JBList; import com.intellij.ui.table.JBTable; +import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; @@ -52,10 +57,14 @@ public class EditLibraryDialog extends DialogWrapper { private JButton myAddFileButton; private JButton myRemoveFileButton; private JBTable myFileTable; + private JButton myAddDocUrlButton; + private JButton myRemoveDocUrlButton; + private JBList myDocUrlList; private Project myProject; private FileTableModel myFileTableModel; private VirtualFile mySelectedFile; private LangScriptingContextProvider myProvider; + private MyDocUrlListModel myDocUrlListModel; public EditLibraryDialog(String title, LangScriptingContextProvider provider, Project project) { super(true); @@ -87,6 +96,44 @@ public class EditLibraryDialog extends DialogWrapper { updateSelection(); } }); + + myDocUrlListModel = new MyDocUrlListModel(); + myDocUrlList.setModel(myDocUrlListModel); + myDocUrlListModel.addListDataListener(new ListDataListener() { + @Override + public void intervalAdded(ListDataEvent e) { + myRemoveDocUrlButton.setEnabled(true); + } + + @Override + public void intervalRemoved(ListDataEvent e) { + Object source = e.getSource(); + if (source instanceof MyDocUrlListModel && ((MyDocUrlListModel)source).getDocUrls().length == 0) { + myRemoveDocUrlButton.setEnabled(false); + } + } + + @Override + public void contentsChanged(ListDataEvent e) { + // do nothing + } + }); + + myAddDocUrlButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + specifyDocUrl(); + } + }); + + myRemoveDocUrlButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + removeDocUrl(); + } + }); + myRemoveDocUrlButton.setEnabled(false); + init(); TableColumn typeCol = myFileTable.getColumnModel().getColumn(FILE_TYPE_COL); @@ -99,6 +146,11 @@ public class EditLibraryDialog extends DialogWrapper { this(title, provider, project); myLibName.setText(lib.getName()); myFileTableModel.setFiles(lib.getSourceFiles(), lib.getCompactFiles()); + String[] docUrls = lib.getDocUrls(); + myDocUrlListModel.setDocUrls(docUrls); + if (docUrls.length > 0) { + myRemoveDocUrlButton.setEnabled(true); + } } private class MyTableCellEditor extends DefaultCellEditor { @@ -311,6 +363,10 @@ public class EditLibraryDialog extends DialogWrapper { public VirtualFile[] getCompactFiles() { return myFileTableModel.getCompactFiles(); } + + public String[] getDocUrls() { + return myDocUrlListModel.getDocUrls(); + } @Override protected void doOKAction() { @@ -324,4 +380,61 @@ public class EditLibraryDialog extends DialogWrapper { private static boolean isLibNameValid(String libName) { return libName != null && libName.matches("\\w[\\w\\d\\._\\-\\d]*"); } + + private static class MyDocUrlListModel extends AbstractListModel { + + private ArrayList myDocUrls = new ArrayList(); + + public void setDocUrls(String[] urls) { + if (urls != null && urls.length > 0) { + myDocUrls.addAll(Arrays.asList(urls)); + } + } + + @Override + public int getSize() { + return myDocUrls.size(); + } + + @Override + public Object getElementAt(int index) { + return myDocUrls.get(index); + } + + public int addUrl(String url) { + myDocUrls.add(url); + int newIndex = myDocUrls.indexOf(url); + fireIntervalAdded(this, newIndex, newIndex); + return newIndex; + } + + public int indexOf(String url) { + return myDocUrls.indexOf(url); + } + + public void remove(String url) { + if (url == null || !myDocUrls.contains(url)) return; + int index = myDocUrls.indexOf(url); + myDocUrls.remove(url); + fireIntervalRemoved(this, index, index); + } + + public String[] getDocUrls() { + return ArrayUtil.toStringArray(myDocUrls); + } + } + + private void specifyDocUrl() { + VirtualFile vf = Util.showSpecifyJavadocUrlDialog(contentPane); + if (vf != null && vf.isValid()) { + String url = vf.getUrl(); + int index = myDocUrlListModel.addUrl(url); + myDocUrlList.ensureIndexIsVisible(index); + myDocUrlList.setSelectedIndex(index); + } + } + + private void removeDocUrl() { + myDocUrlListModel.remove((String)myDocUrlList.getSelectedValue()); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/ScriptingLibrariesPanel.java b/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/ScriptingLibrariesPanel.java index 603dd4088551..b41ea3e2ff23 100644 --- a/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/ScriptingLibrariesPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/scriptingContext/ui/ScriptingLibrariesPanel.java @@ -96,7 +96,8 @@ public class ScriptingLibrariesPanel extends ScriptingLibrariesPanelStub { EditLibraryDialog editLibDialog = new EditLibraryDialog("New Library", myProvider, myProject); editLibDialog.show(); if (editLibDialog.isOK()) { - myLibTableModel.createLibrary(editLibDialog.getLibName(), editLibDialog.getSourceFiles(), editLibDialog.getCompactFiles(), null); + myLibTableModel.createLibrary(editLibDialog.getLibName(), editLibDialog.getSourceFiles(), editLibDialog.getCompactFiles(), + editLibDialog.getDocUrls()); } } @@ -129,7 +130,8 @@ public class ScriptingLibrariesPanel extends ScriptingLibrariesPanelStub { editLibDialog.show(); if (editLibDialog.isOK()) { myLibTableModel - .updateLibrary(libName, editLibDialog.getLibName(), editLibDialog.getSourceFiles(), editLibDialog.getCompactFiles(), null); + .updateLibrary(libName, editLibDialog.getLibName(), editLibDialog.getSourceFiles(), editLibDialog.getCompactFiles(), + editLibDialog.getDocUrls()); } } } diff --git a/platform/lang-impl/src/com/intellij/injected/editor/FoldingModelWindow.java b/platform/lang-impl/src/com/intellij/injected/editor/FoldingModelWindow.java index 6e880586fcac..9128fbb58f92 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/FoldingModelWindow.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/FoldingModelWindow.java @@ -63,7 +63,7 @@ public class FoldingModelWindow implements FoldingModelEx{ } public FoldRegion addFoldRegion(int startOffset, int endOffset, @NotNull String placeholderText) { - FoldRegion region = createFoldRegion(startOffset, endOffset, placeholderText, null); + FoldRegion region = createFoldRegion(startOffset, endOffset, placeholderText, null, false); if (region == null) return null; if (!addFoldRegion(region)) { region.dispose(); @@ -129,10 +129,10 @@ public class FoldingModelWindow implements FoldingModelEx{ } private static final Key FOLD_REGION_WINDOW = Key.create("FOLD_REGION_WINDOW"); - public FoldRegion createFoldRegion(int startOffset, int endOffset, @NotNull String placeholder, FoldingGroup group) { + public FoldRegion createFoldRegion(int startOffset, int endOffset, @NotNull String placeholder, FoldingGroup group, boolean neverExpands) { TextRange hostRange = myDocumentWindow.injectedToHost(new TextRange(startOffset, endOffset)); if (hostRange.getLength() < 2) return null; - FoldRegion hostRegion = myDelegate.createFoldRegion(hostRange.getStartOffset(), hostRange.getEndOffset(), placeholder, group); + FoldRegion hostRegion = myDelegate.createFoldRegion(hostRange.getStartOffset(), hostRange.getEndOffset(), placeholder, group, false); FoldingRegionWindow window = new FoldingRegionWindow(myDocumentWindow, myEditorWindow, (FoldRegionImpl)hostRegion); hostRegion.putUserData(FOLD_REGION_WINDOW, window); return window; diff --git a/platform/lang-impl/src/com/intellij/injected/editor/FoldingRegionWindow.java b/platform/lang-impl/src/com/intellij/injected/editor/FoldingRegionWindow.java index adf45f9ec76b..41c6994b95fe 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/FoldingRegionWindow.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/FoldingRegionWindow.java @@ -56,6 +56,11 @@ public class FoldingRegionWindow extends RangeMarkerWindow implements FoldRegion return myHostRegion.getGroup(); } + @Override + public boolean shouldNeverExpand() { + return false; + } + public FoldRegionImpl getDelegate() { return myHostRegion; } diff --git a/platform/lang-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java b/platform/lang-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java index 896911a5ce1e..5d9f5e95ea24 100644 --- a/platform/lang-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java +++ b/platform/lang-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java @@ -93,7 +93,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { private int myLexemeCount = 0; private boolean myTokenTypeChecked; private ITokenTypeRemapper myRemapper; - private WhitespaceSkippedCallback myWhispaceSkippedCallback; + private WhitespaceSkippedCallback myWhitespaceSkippedCallback; private ASTNode myOriginalTree = null; @@ -620,13 +620,22 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { @Nullable @Override public IElementType lookAhead(int steps) { - if (steps + myCurrentLexeme >= myLexemeCount) return null; - return myLexTypes[myCurrentLexeme + steps]; + int cur = myCurrentLexeme; + + while (steps > 0) { + while (cur < myLexemeCount && whitespaceOrComment(myLexTypes[cur])) { + cur++; + } + + steps--; + } + + return cur < myLexemeCount ? myLexTypes[cur] : null; } @Override public void setWhitespaceSkippedCallback(WhitespaceSkippedCallback callback) { - myWhispaceSkippedCallback = callback; + myWhitespaceSkippedCallback = callback; } public void advanceLexer() { @@ -647,8 +656,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { } private void onSkip(IElementType type, int start, int end) { - if (myWhispaceSkippedCallback != null) { - myWhispaceSkippedCallback.onSkip(type, start, end); + if (myWhitespaceSkippedCallback != null) { + myWhitespaceSkippedCallback.onSkip(type, start, end); } } diff --git a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java index a02cc0d7afd5..b272e9bf6a52 100644 --- a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java @@ -37,6 +37,7 @@ import com.intellij.openapi.module.impl.scopes.ModuleWithDependentsScope; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.impl.storage.ClasspathStorage; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.PathUtil; @@ -322,16 +323,12 @@ public class ModuleImpl extends ComponentManagerImpl implements Module { @SuppressWarnings({"HardCodedStringLiteral"}) public String toString() { - return "Module:" + getName() + " path:" + getModuleFilePath(); + if (myName == null) return "Module"; // was called before initialized + return "Module: '" + getName() + "' path: '" + getModuleFilePath()+"'"; } - private static String moduleNameByFileName(String fileName) { - if (fileName.endsWith(ModuleFileType.DOT_DEFAULT_EXTENSION)) { - return fileName.substring(0, fileName.length() - ModuleFileType.DOT_DEFAULT_EXTENSION.length()); - } - else { - return fileName; - } + private static String moduleNameByFileName(@NotNull String fileName) { + return StringUtil.trimEnd(fileName, ModuleFileType.DOT_DEFAULT_EXTENSION); } public T[] getExtensions(final ExtensionPointName extensionPointName) { diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java index c70c5a9a947f..579272d74eb0 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java @@ -48,21 +48,22 @@ abstract class OrderEnumeratorBase extends OrderEnumerator { protected boolean myRecursivelyExportedOnly; private boolean myExportedOnly; private Condition myCondition; - private List myCustomHandlers; + private final List myCustomHandlers; protected ModulesProvider myModulesProvider; private OrderRootsCache myCache; public OrderEnumeratorBase(@Nullable Module module, @NotNull Project project, @Nullable OrderRootsCache cache) { myCache = cache; + List customHandlers = null; for (OrderEnumerationHandler handler : OrderEnumerationHandler.EP_NAME.getExtensions()) { if (handler.isApplicable(project) && (module == null || handler.isApplicable(module))) { - if (myCustomHandlers == null) { - myCustomHandlers = new SmartList(); + if (customHandlers == null) { + customHandlers = new SmartList(); } - myCustomHandlers.add(handler); + customHandlers.add(handler); } - if (myCustomHandlers == null) myCustomHandlers = Collections.emptyList(); } + this.myCustomHandlers = customHandlers == null ? Collections.emptyList() : customHandlers; } @Override diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java index 6ea3c5b79d57..1e6c8a78cfe3 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -451,6 +451,25 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec int psiEndOffset = textBlock.getPsiEndOffset(); endOffset = psiEndOffset; lengthShift = textBlock.getTextEndOffset() - psiEndOffset; + + if (oldText != null) { + String psiPrefix = oldText.substring(0, startOffset); + String docPrefix = chars.subSequence(0, startOffset).toString(); + String psiSuffix = oldText.substring(psiEndOffset); + String docSuffix = chars.subSequence(textBlock.getTextEndOffset(), chars.length()).toString(); + if (!psiPrefix.equals(docPrefix) || !psiSuffix.equals(docSuffix)) { + String msg = "PSI/document inconsistency before reparse: "; + if (!psiPrefix.equals(docPrefix)) { + msg = msg + "psiPrefix=" + psiPrefix + "; docPrefix=" + docPrefix + ";"; + } + if (!psiSuffix.equals(docSuffix)) { + msg = msg + "psiSuffix=" + psiSuffix + "; docSuffix=" + docSuffix + ";"; + } + throw new AssertionError(msg); + } + } else if (document.getTextLength() - textBlock.getTextEndOffset() != file.getTextLength() - psiEndOffset) { + throw new AssertionError("PSI/document inconsistency before reparse: file=" + file); + } } else { startOffset = 0; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentTransactionListener.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentTransactionListener.java index 0334dd6d2dda..02c61db3d138 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentTransactionListener.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentTransactionListener.java @@ -24,8 +24,8 @@ import com.intellij.psi.PsiFile; import com.intellij.util.messages.Topic; public interface PsiDocumentTransactionListener { - Topic TOPIC = new Topic("psi.DocumentTransactionListener", PsiDocumentTransactionListener.class, Topic.BroadcastDirection.TO_PARENT); + Topic TOPIC = new Topic("psi.DocumentTransactionListener", PsiDocumentTransactionListener.class, Topic.BroadcastDirection.TO_PARENT); void transactionStarted(Document doc, PsiFile file); void transactionCompleted(Document doc, PsiFile file); -} \ No newline at end of file +} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/DummyHolder.java b/platform/lang-impl/src/com/intellij/psi/impl/source/DummyHolder.java index b6009113df3c..f6d4d1e28b54 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/DummyHolder.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/DummyHolder.java @@ -56,7 +56,12 @@ public class DummyHolder extends PsiFileImpl { ((DummyHolderViewProvider)getViewProvider()).setDummyHolder(this); myContext = context; myTable = table != null ? table : IdentityCharTable.INSTANCE; - if(contentElement != null) { + if (contentElement instanceof FileElement) { + myFileElement = (FileElement)contentElement; + myFileElement.setPsi(this); + if (myTable != null) myFileElement.setCharTable(myTable); + } + else if (contentElement != null) { getTreeElement().rawAddChildren(contentElement); clearCaches(); } @@ -81,7 +86,7 @@ public class DummyHolder extends PsiFileImpl { } public boolean isValid() { - if(myExplicitlyValid != null) return myExplicitlyValid.booleanValue(); + if (myExplicitlyValid != null) return myExplicitlyValid.booleanValue(); return super.isValid() && !(myContext != null && !myContext.isValid()); } @@ -112,10 +117,10 @@ public class DummyHolder extends PsiFileImpl { } public FileElement getTreeElementNoLock() { - if(myFileElement == null){ + if (myFileElement == null) { myFileElement = new FileElement(TokenType.DUMMY_HOLDER, null); myFileElement.setPsi(this); - if(myTable != null) myFileElement.setCharTable(myTable); + if (myTable != null) myFileElement.setCharTable(myTable); clearCaches(); } return myFileElement; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index ee68ffffac2e..4dcc859f131b 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -909,24 +909,30 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF } private void bindStubs(final ASTNode tree, final Iterator> stubs, final StubBuilder builder) { - final IElementType type = tree.getElementType(); + ((TreeElement)tree).acceptTree(new RecursiveTreeElementWalkingVisitor() { + @Override + protected void visitNode(TreeElement root) { + CompositeElement parent = root.getTreeParent(); + IElementType parentType = parent == null ? null : parent.getElementType(); + final IElementType type = root.getElementType(); + if (parentType != null && builder.skipChildProcessingWhenBuildingStubs(parentType, type)) { + return; + } - if (type instanceof IStubElementType && ((IStubElementType) type).shouldCreateStub(tree)) { - final StubElement stub = stubs.hasNext() ? stubs.next() : null; - if (stub == null || stub.getStubType() != tree.getElementType()) { - rebuildStub(); - assert false : "Stub and PSI element type mismatch in " + getName() + ": stub:" + stub + ", AST:" + tree.getElementType(); + if (type instanceof IStubElementType && ((IStubElementType) type).shouldCreateStub(root)) { + final StubElement stub = stubs.hasNext() ? stubs.next() : null; + if (stub == null || stub.getStubType() != type) { + rebuildStub(); + assert false : "Stub and PSI element type mismatch in " + getName() + ": stub:" + stub + ", AST:" + type; + } + + //noinspection unchecked + ((StubBase)stub).setPsi(root.getPsi()); + } + + super.visitNode(root); } - - //noinspection unchecked - ((StubBase)stub).setPsi(tree.getPsi()); - } - - for (ASTNode node : tree.getChildren(null)) { - if (!builder.skipChildProcessingWhenBuildingStubs(type, node.getElementType())) { - bindStubs(node, stubs, builder); - } - } + }); } private void rebuildStub() { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/SourceTreeToPsiMap.java b/platform/lang-impl/src/com/intellij/psi/impl/source/SourceTreeToPsiMap.java index 947be673102c..e2c777821e95 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/SourceTreeToPsiMap.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/SourceTreeToPsiMap.java @@ -23,20 +23,21 @@ import com.intellij.psi.impl.source.tree.TreeElement; import org.jetbrains.annotations.Nullable; public class SourceTreeToPsiMap { - private SourceTreeToPsiMap() { - } + private SourceTreeToPsiMap() { } - public static PsiElement treeElementToPsi(@Nullable ASTNode element) { + @Nullable + public static PsiElement treeElementToPsi(@Nullable final ASTNode element) { if (element == null) return null; return element.getPsi(); } - public static ASTNode psiElementToTree(@Nullable PsiElement psiElement) { + @Nullable + public static ASTNode psiElementToTree(@Nullable final PsiElement psiElement) { if (psiElement == null) return null; return psiElement.getNode(); } - public static boolean hasTreeElement(@Nullable PsiElement psiElement) { + public static boolean hasTreeElement(@Nullable final PsiElement psiElement) { return psiElement instanceof TreeElement || psiElement instanceof ASTDelegatePsiElement || psiElement instanceof PsiFileImpl; } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java index 4765185d4220..b4318b65923b 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java @@ -23,6 +23,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.tree.events.ChangeInfo; import com.intellij.pom.tree.events.TreeChangeEvent; import com.intellij.pom.tree.events.impl.ChangeInfoImpl; @@ -388,7 +389,8 @@ public class CompositeElement extends TreeElement { } catch (AssertionError e) { myCachedLength = NOT_CACHED; - LOG.error("===\n"+PerformanceWatcher.dumpThreadsToString()+"\n===\n", e); + String assertion = StringUtil.getThrowableText(e); + LOG.error("Walking failure: ===\n"+assertion+"\n=== Thread dump:\n"+PerformanceWatcher.dumpThreadsToString()+"\n===\n"); } return myCachedLength; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java index 76472f3e5eb9..b6290097e660 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java @@ -60,10 +60,9 @@ public class InjectedLanguageUtil { }); } - private static PsiElement loadTree(PsiElement host) { - PsiFile file = host.getContainingFile(); - if (file instanceof DummyHolder) { - PsiElement context = file.getContext(); + private static PsiElement loadTree(PsiElement host, PsiFile containingFile) { + if (containingFile instanceof DummyHolder) { + PsiElement context = containingFile.getContext(); if (context != null) { PsiFile topFile = context.getContainingFile(); topFile.getNode(); //load tree @@ -81,7 +80,7 @@ public class InjectedLanguageUtil { @Nullable public static List> getInjectedPsiFiles(@NotNull final PsiElement host) { - final PsiElement inTree = loadTree(host); + final PsiElement inTree = loadTree(host, host.getContainingFile()); final List> result = new SmartList>(); enumerate(inTree, new PsiLanguageInjectionHost.InjectedPsiVisitor() { public void visit(@NotNull PsiFile injectedPsi, @NotNull List places) { @@ -125,7 +124,7 @@ public class InjectedLanguageUtil { if (file == null || !file.isPhysical() && file.getOriginalFile() == file) return; } - PsiElement inTree = loadTree(host); + PsiElement inTree = loadTree(host, containingFile); if (inTree != host) { host = inTree; containingFile = host.getContainingFile(); diff --git a/platform/platform-api/src/com/intellij/openapi/editor/FoldRegion.java b/platform/platform-api/src/com/intellij/openapi/editor/FoldRegion.java index 13bd2e1941fd..819e87c84639 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/FoldRegion.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/FoldRegion.java @@ -53,4 +53,6 @@ public interface FoldRegion extends RangeMarker { @Nullable FoldingGroup getGroup(); + + boolean shouldNeverExpand(); } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java index 967538d37dbb..6fd58d6ddd64 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java @@ -377,7 +377,7 @@ public class HintManagerImpl extends HintManager implements Disposable { Dimension size = hint.getComponent().getPreferredSize(); if (hint.isRealPopup()) { - final Point editorCorner = editor.getContentComponent().getLocation(); + final Point editorCorner = editor.getComponent().getLocation(); SwingUtilities.convertPointToScreen(editorCorner, layeredPane); final Rectangle editorScreen = ScreenUtil.getScreenRectangle(editorCorner.x, editorCorner.y); diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginsUsagesCollector.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginsUsagesCollector.java new file mode 100644 index 000000000000..560fac29c488 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginsUsagesCollector.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2010 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.ide.plugins; + +import com.intellij.openapi.project.Project; +import com.intellij.statistic.UsagesCollector; +import com.intellij.statistic.beans.GroupDescriptor; +import com.intellij.statistic.beans.UsageDescriptor; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +public class PluginsUsagesCollector extends UsagesCollector { + private static final String GROUP_ID = "plugins"; + + public static GroupDescriptor getGroupId() { + return GroupDescriptor.create(GROUP_ID, GroupDescriptor.HIGHER_PRIORITY); + } + + @NotNull + public Set getUsages(@Nullable Project project) { + return ContainerUtil.map2Set(PluginManager.getPlugins(), new Function() { + @Override + public UsageDescriptor fun(IdeaPluginDescriptor descriptor) { + return new UsageDescriptor(getGroupId(), descriptor.getName(), 1); + } + }); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index 3c97e046ecc8..f318d33732ec 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -1196,4 +1196,9 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application return false; } + + @Override + public String toString() { + return "Application"; + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java index 4bfd0229c027..1ec7ae1ea7c7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java @@ -59,7 +59,7 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap private static final int COMMAND_TO_RUN_COMPACT = 20; private static final int FREE_QUEUES_LIMIT = 30; - private final ProjectEx myProject; + @Nullable private final ProjectEx myProject; private final CommandProcessor myCommandProcessor; private final StartupManager myStartupManager; @@ -110,6 +110,7 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap return "UndoManager"; } + @Nullable public Project getProject() { return myProject; } @@ -337,7 +338,9 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap Runnable executeUndoOrRedoAction = new Runnable() { public void run() { try { - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + if (myProject != null) { + PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + } myMerger.undoOrRedo(editor, isUndo); } catch (RuntimeException ex) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/BackspaceAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/BackspaceAction.java index 86b8b771ee11..ac2e83ba850e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/BackspaceAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/BackspaceAction.java @@ -83,8 +83,16 @@ public class BackspaceAction extends EditorAction { int offset = editor.getCaretModel().getOffset(); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); editor.getSelectionModel().removeSelection(); - document.deleteString(offset-1, offset); - editor.getCaretModel().moveToOffset(offset - 1, true); + + FoldRegion region = editor.getFoldingModel().getCollapsedRegionAtOffset(offset - 1); + if (region != null && region.shouldNeverExpand()) { + document.deleteString(region.getStartOffset(), region.getEndOffset()); + editor.getCaretModel().moveToOffset(region.getStartOffset()); + } + else { + document.deleteString(offset - 1, offset); + editor.getCaretModel().moveToOffset(offset - 1, true); + } } } else if(lineNumber > 0) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/DeleteAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/DeleteAction.java index 6bfb0a282bed..b5d9ad63f2b1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/DeleteAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/DeleteAction.java @@ -96,12 +96,19 @@ public class DeleteAction extends EditorAction { Document document = editor.getDocument(); if(afterLineEnd < 0) { int offset = editor.getCaretModel().getOffset(); - document.deleteString(offset, offset + 1); - editor.getCaretModel().moveToOffset(offset); + FoldRegion region = editor.getFoldingModel().getCollapsedRegionAtOffset(offset); + if (region != null && region.shouldNeverExpand()) { + document.deleteString(region.getStartOffset(), region.getEndOffset()); + editor.getCaretModel().moveToOffset(region.getStartOffset()); + } + else { + document.deleteString(offset, offset + 1); + editor.getCaretModel().moveToOffset(offset); + } return; } - if(lineNumber + 1 >= document.getLineCount()) - return; + + if(lineNumber + 1 >= document.getLineCount()) return; // Do not group delete newline and other deletions. CommandProcessor commandProcessor = CommandProcessor.getInstance(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/FoldingModelEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/FoldingModelEx.java index 82a35ca5b52d..efdeae2a7a2c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/FoldingModelEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/FoldingModelEx.java @@ -44,7 +44,7 @@ public interface FoldingModelEx extends FoldingModel { FoldRegion[] fetchTopLevel(); @Nullable - FoldRegion createFoldRegion(int startOffset, int endOffset, @NotNull String placeholder, FoldingGroup group); + FoldRegion createFoldRegion(int startOffset, int endOffset, @NotNull String placeholder, FoldingGroup group, boolean neverExpands); boolean addListener(@NotNull FoldingListener listener); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorDocumentPriorities.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorDocumentPriorities.java index 79cf1924369c..991248350268 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorDocumentPriorities.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorDocumentPriorities.java @@ -32,8 +32,8 @@ public class EditorDocumentPriorities { */ public static final int RANGE_MARKER = 40; - public static final int SOFT_WRAP_MODEL = 60; - public static final int FOLD_MODEL = 80; + public static final int FOLD_MODEL = 60; + public static final int SOFT_WRAP_MODEL = 80; public static final int LEXER_EDITOR = 100; public static final int CARET_MODEL = 120; public static final int SELECTION_MODEL = 140; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 97c7f27a0238..90a56ca7cea2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -2356,7 +2356,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi if (i < softWrapChars.length - 1) { position.x = 0; // Soft wrap starts new visual line position.x = drawString( - g, softWrapChars, i + 1, softWrapChars.length, position, clip, effectColor, effectType, fontType, fontColor + g, softWrapChars, i + 1, softWrapChars.length, position, clip, null, null, fontType, fontColor ); } position.x += mySoftWrapModel.paint(g, SoftWrapDrawingType.AFTER_SOFT_WRAP, position.x, position.y, getLineHeight()); @@ -2367,7 +2367,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi // Draw token text before the wrap. if (softWrap.getStart() > startToUse) { position.x = drawString( - g, text, startToUse, softWrap.getStart(), position, clip, effectColor, effectType, fontType, fontColor + g, text, startToUse, softWrap.getStart(), position, clip, null, null, fontType, fontColor ); } @@ -2385,7 +2385,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi // Draw soft wrap symbols on current visual line if any. if (i - softWrapSegmentStartIndex > 0) { drawString( - g, softWrapChars, softWrapSegmentStartIndex, i, position, clip, effectColor, effectType, fontType, fontColor + g, softWrapChars, softWrapSegmentStartIndex, i, position, clip, null, null, fontType, fontColor ); } mySoftWrapModel.paint(g, SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED, position.x, position.y, getLineHeight()); @@ -2405,8 +2405,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi // Draw remaining soft wrap symbols from its last line if any. if (softWrapSegmentStartIndex < softWrapChars.length) { position.x += drawString( - g, softWrapChars, softWrapSegmentStartIndex, softWrapChars.length, position, clip, effectColor, effectType, - fontType, fontColor + g, softWrapChars, softWrapSegmentStartIndex, softWrapChars.length, position, clip, null, null, fontType, fontColor ); } position.x += mySoftWrapModel.paint(g, SoftWrapDrawingType.AFTER_SOFT_WRAP, position.x, position.y, getLineHeight()); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionImpl.java index 94a6b9b2c6c8..903ce99efcc1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionImpl.java @@ -36,10 +36,17 @@ public class FoldRegionImpl extends RangeMarkerImpl implements FoldRegion { private final Editor myEditor; private final String myPlaceholderText; private final FoldingGroup myGroup; + private final boolean myShouldNeverExpand; - FoldRegionImpl(@NotNull Editor editor, int startOffset, int endOffset, @NotNull String placeholder, FoldingGroup group) { + FoldRegionImpl(@NotNull Editor editor, + int startOffset, + int endOffset, + @NotNull String placeholder, + FoldingGroup group, + boolean shouldNeverExpand) { super((DocumentEx)editor.getDocument(), startOffset, endOffset); myGroup = group; + myShouldNeverExpand = shouldNeverExpand; myIsExpanded = true; myEditor = editor; myPlaceholderText = placeholder; @@ -91,6 +98,11 @@ public class FoldRegionImpl extends RangeMarkerImpl implements FoldRegion { return myGroup; } + @Override + public boolean shouldNeverExpand() { + return myShouldNeverExpand; + } + public String toString() { return "FoldRegion " + (isExpanded() ? "-" : "+") + "(" + getStartOffset() + ":" + getEndOffset() + ")" + (isValid() ? "" : "(invalid)"); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java index 2053ec7846fb..f46d773a9f57 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java @@ -142,7 +142,7 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList } public FoldRegion addFoldRegion(int startOffset, int endOffset, @NotNull String placeholderText) { - FoldRegion region = createFoldRegion(startOffset, endOffset, placeholderText, null); + FoldRegion region = createFoldRegion(startOffset, endOffset, placeholderText, null, false); if (region == null) return null; if (!addFoldRegion(region)) { region.dispose(); @@ -167,9 +167,9 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList final FoldingGroup group = region.getGroup(); if (group != null) { myGroups.putValue(group, region); - for (FoldingListener listener : myListeners) { - listener.onFoldRegionStateChange(region); - } + } + for (FoldingListener listener : myListeners) { + listener.onFoldRegionStateChange(region); } return true; } @@ -267,7 +267,7 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList public void expandFoldRegion(FoldRegion region) { assertIsDispatchThread(); - if (region.isExpanded()) return; + if (region.isExpanded() || region.shouldNeverExpand()) return; if (!myIsBatchFoldingProcessing) { LOG.error("Fold regions must be collapsed or expanded inside batchFoldProcessing() only."); @@ -456,8 +456,8 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList return EditorDocumentPriorities.FOLD_MODEL; } - public FoldRegion createFoldRegion(int startOffset, int endOffset, @NotNull String placeholder, FoldingGroup group) { - FoldRegionImpl region = new FoldRegionImpl(myEditor, startOffset, endOffset, placeholder, group); + public FoldRegion createFoldRegion(int startOffset, int endOffset, @NotNull String placeholder, FoldingGroup group, boolean neverExpands) { + FoldRegionImpl region = new FoldRegionImpl(myEditor, startOffset, endOffset, placeholder, group, neverExpands); region.registerInDocument(); LOG.assertTrue(region.isValid()); return region; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java index af88b5231bd8..a2a1975a9759 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java @@ -76,6 +76,17 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi private int myActive; private boolean myUseSoftWraps; + /** + * Soft wraps need to be kept up-to-date on all editor modification (changing text, adding/removing/expanding/collapsing fold + * regions etc). Hence, we need to react to all types of target changes. However, soft wraps processing uses various information + * provided by editor and there is a possible case that that information is inconsistent during update time (e.g. fold model + * advances fold region offsets when end-user types before it, hence, fold regions data is inconsistent between the moment + * when text changes are applied to the document and fold data is actually updated). + *

+ * Current field serves as a flag that indicates if all preliminary actions necessary for successful soft wraps processing is done. + */ + private boolean myUpdateInProgress; + public SoftWrapModelImpl(@NotNull EditorEx editor) { this(editor, new SoftWrapsStorage(), new CompositeSoftWrapPainter(editor)); } @@ -271,7 +282,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi @NotNull @Override public LogicalPosition visualToLogicalPosition(@NotNull VisualPosition visual) { - if (!prepareToMapping()) { + if (myUpdateInProgress || !prepareToMapping()) { return myEditor.visualToLogicalPosition(visual, false); } myActive++; @@ -287,7 +298,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi @NotNull @Override public LogicalPosition offsetToLogicalPosition(int offset) { - if (!prepareToMapping()) { + if (myUpdateInProgress || !prepareToMapping()) { return myEditor.offsetToLogicalPosition(offset, false); } myActive++; @@ -302,7 +313,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi @NotNull public LogicalPosition adjustLogicalPosition(LogicalPosition defaultLogical, int offset) { - if (!prepareToMapping()) { + if (myUpdateInProgress || !prepareToMapping()) { return defaultLogical; } @@ -318,7 +329,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi @NotNull public VisualPosition adjustVisualPosition(@NotNull LogicalPosition logical, @NotNull VisualPosition defaultVisual) { - if (!prepareToMapping()) { + if (myUpdateInProgress || !prepareToMapping()) { return defaultVisual; } @@ -477,6 +488,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi @Override public void beforeDocumentChange(DocumentEvent event) { + myUpdateInProgress = true; if (!isSoftWrappingEnabled()) { return; } @@ -487,6 +499,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi @Override public void documentChanged(DocumentEvent event) { + myUpdateInProgress = false; if (!isSoftWrappingEnabled()) { return; } @@ -497,6 +510,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi @Override public void onFoldRegionStateChange(@NotNull FoldRegion region) { + myUpdateInProgress = true; if (!isSoftWrappingEnabled() || !region.isValid()) { return; } @@ -507,6 +521,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi @Override public void onFoldProcessingEnd() { + myUpdateInProgress = false; if (!isSoftWrappingEnabled()) { return; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java index 6c6da2a5a619..518b073d1c14 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java @@ -199,7 +199,7 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen processNonFoldToken(); } else { - boolean continueProcessing = processCollapsedFoldRegion(currentFold, event); + boolean continueProcessing = processCollapsedFoldRegion(currentFold); if (!continueProcessing) { return false; } @@ -224,11 +224,10 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen * Encapsulates logic of processing given collapsed fold region. * * @param foldRegion target collapsed fold region to process - * @param event change event that triggered the processing * @return true if processing should be continued; false otherwise */ - private boolean processCollapsedFoldRegion(FoldRegion foldRegion, IncrementalCacheUpdateEvent event) { - if (processOutOfDateFoldRegion(foldRegion, event)) { + private boolean processCollapsedFoldRegion(FoldRegion foldRegion) { + if (processOutOfDateFoldRegion(foldRegion)) { return false; } @@ -298,11 +297,10 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen * This method encapsulates logic for checking and reacting on such a situation. * * @param foldRegion fold region that may be out-of-date - * @param event change event that triggered the processing * @return true if given fold region is really out-of-date and processing should be stopped; * false otherwise; */ - private boolean processOutOfDateFoldRegion(FoldRegion foldRegion, IncrementalCacheUpdateEvent event) { + private boolean processOutOfDateFoldRegion(FoldRegion foldRegion) { Document document = myEditor.getDocument(); @@ -310,17 +308,11 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen // case that offsets of the trailing fold regions should be updated as well. IncrementalCacheUpdateEvent newEvent = new IncrementalCacheUpdateEvent(document); - // We assume here that fold model is processed after soft wrap (as it needs to perform document dimensions mapping). - // So, there is a possible case that user performed modifications at particular fold region but fold model is not updated yet - // and IterationState returns valid fold region. Hence, we introduce a dedicated check here. - if (!foldRegion.isValid() || (event.getExactOffsetsDiff() != 0 && foldRegion.getStartOffset() < event.getOldExactEndOffset() - && foldRegion.getEndOffset() > event.getOldExactStartOffset()) || myContext.tokenStartOffset != foldRegion.getStartOffset()) - { + if (!foldRegion.isValid() || myContext.tokenStartOffset != foldRegion.getStartOffset()) { myEventsStorage.add(document, newEvent); return true; } - if (foldRegion.getEndOffset() <= document.getTextLength()) { return false; } diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java index baf26ab22705..3eef1133d039 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java @@ -220,6 +220,7 @@ public class ProjectImpl extends ComponentManagerImpl implements ProjectEx { @Nullable @NonNls public String getLocation() { + if (myName == null) return null; // was called before initialized return isDisposed() ? null : getStateStore().getLocation(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index 5087a4875bbe..96dd3cfe0ad3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -354,6 +354,8 @@ public final class UpdateChecker { } catch (Exception ignored) { } + catch (InternalError ignored) { + } propertiesComponent.setValue(INSTALLATION_UID, uid); } else { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java index eaa418ecc099..535555f728f1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java @@ -565,10 +565,12 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { if (parentFile != null) { // I hope ls works fast on Unix final String[] canonicalFileNames = parentFile.list(); - for (String name : canonicalFileNames) { - // if names are equals - if (name.compareToIgnoreCase(originalFileName) == 0) { - return name; + if (canonicalFileNames != null) { + for (String name : canonicalFileNames) { + // if names are equals + if (name.compareToIgnoreCase(originalFileName) == 0) { + return name; + } } } } diff --git a/platform/platform-impl/src/com/intellij/ui/Hint.java b/platform/platform-impl/src/com/intellij/ui/Hint.java index 4acbb0c639a2..451ee6fbffd9 100644 --- a/platform/platform-impl/src/com/intellij/ui/Hint.java +++ b/platform/platform-impl/src/com/intellij/ui/Hint.java @@ -20,6 +20,9 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; +/** + * @see #hide() + */ public interface Hint { /** * @param parentComponent defines coordinate system where hint will be shown. @@ -36,6 +39,13 @@ public interface Hint { */ boolean isVisible(); + /** + * Hides current hint object. + *

+ * Note: this method is also used as a destruction callback, i.e. it performs necessary de-initialization when + * current hint is not necessary to use anymore. Hence, it's necessary to call it from place where you definitely + * now that current hint will not be used. + */ void hide(); void addHintListener(HintListener listener); diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 97b83f71b0d1..b32905628a95 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -1081,6 +1081,8 @@ goto.inspection.action.text=&Run Inspection by Name... label.no.inspections.found=No inspections found #Scripting library management +scripting.lib.name=&Name +scripting.lib.file.title=Files scripting.lib.file.location=Location scripting.lib.file.type=Type scripting.lib.select.root=Select library file or directory @@ -1090,6 +1092,9 @@ scripting.lib.detach=&Detach scripting.lib.add=&Add... scripting.lib.edit=&Edit... scripting.lib.remove=&Remove +scripting.lib.docUrl.specify=&Specify... +scripting.lib.docUrl.remove=&Remove +scripting.lib.docUrl.title=Documentation URLs scripting.lib.usageScope=Usage Scope scripting.lib.usageScope.caption=Specify which libraries are used in specific files and/or directories. scripting.lib.usageScope.tableTitle=Library diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 799d7cb0a1cc..caa86f0b81a0 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -204,5 +204,6 @@ + diff --git a/platform/testFramework/src/com/intellij/mock/MockFoldRegion.java b/platform/testFramework/src/com/intellij/mock/MockFoldRegion.java index 51b2e051ea5a..2c9c77c11cc3 100644 --- a/platform/testFramework/src/com/intellij/mock/MockFoldRegion.java +++ b/platform/testFramework/src/com/intellij/mock/MockFoldRegion.java @@ -67,6 +67,11 @@ public class MockFoldRegion extends UserDataHolderBase implements FoldRegion { throw new UnsupportedOperationException("FoldRegion.getGroup() is not implemented yet at " + getClass()); } + @Override + public boolean shouldNeverExpand() { + return false; + } + @NotNull @Override public Document getDocument() { diff --git a/platform/testFramework/src/com/intellij/testFramework/LoggedErrorProcessor.java b/platform/testFramework/src/com/intellij/testFramework/LoggedErrorProcessor.java index 769916a183b6..18be4a3942cb 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LoggedErrorProcessor.java +++ b/platform/testFramework/src/com/intellij/testFramework/LoggedErrorProcessor.java @@ -19,8 +19,7 @@ import org.apache.log4j.Logger; import org.jetbrains.annotations.NonNls; @NonNls public abstract class LoggedErrorProcessor { - - private final static LoggedErrorProcessor DEFAULT = new LoggedErrorProcessor() { + private static final LoggedErrorProcessor DEFAULT = new LoggedErrorProcessor() { @Override public void processError(String message, Throwable t, String[] details, Logger logger) { logger.info(message, t); @@ -28,8 +27,8 @@ import org.jetbrains.annotations.NonNls; t.printStackTrace(); if (details != null && details.length > 0) { System.out.println("details: "); - for (int i = 0; i < details.length; i++) { - System.out.println(details[i]); + for (String detail : details) { + System.out.println(detail); } } diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 34b301878989..7e8ac5b0ae7d 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -795,7 +795,7 @@ public class StringUtil { @NotNull public static String trimEnd(@NotNull String s, @NonNls @NotNull String suffix) { if (s.endsWith(suffix)) { - return s.substring(0, s.lastIndexOf(suffix)); + return s.substring(0, s.length() - suffix.length()); } return s; } @@ -1087,6 +1087,22 @@ public class StringUtil { return result.toString(); } + @NotNull + public static String join(final String... strings) { + if (strings == null || strings.length == 0) return ""; + + final StringBuilder builder = StringBuilderSpinAllocator.alloc(); + try { + for (final String string : strings) { + builder.append(string); + } + return builder.toString(); + } + finally { + StringBuilderSpinAllocator.dispose(builder); + } + } + @NotNull public static String stripQuotesAroundValue(@NotNull String text) { if (startsWithChar(text, '\"') || startsWithChar(text, '\'')) text = text.substring(1); diff --git a/platform/util/src/com/intellij/util/messages/impl/MessageBusConnectionImpl.java b/platform/util/src/com/intellij/util/messages/impl/MessageBusConnectionImpl.java index f0ad663f76b2..be84fd2683d1 100644 --- a/platform/util/src/com/intellij/util/messages/impl/MessageBusConnectionImpl.java +++ b/platform/util/src/com/intellij/util/messages/impl/MessageBusConnectionImpl.java @@ -47,25 +47,18 @@ public class MessageBusConnectionImpl implements MessageBusConnection { } public void subscribe(Topic topic, L handler) { - if (mySubscriptions.containsKey(topic)) { + if (mySubscriptions.put(topic, handler) != null) { throw new IllegalStateException("Subscription to " + topic + " already exists"); } - - mySubscriptions.put(topic, handler); myBus.notifyOnSubscription(this, topic); } public void subscribe(Topic topic) { - if (mySubscriptions.containsKey(topic)) { - throw new IllegalStateException("Subscription to " + topic + " already exists"); - } - if (myDefaultHandler == null) { throw new IllegalStateException("Connection must have default handler installed prior to any anonymous subscriptions."); } - mySubscriptions.put(topic, myDefaultHandler); - myBus.notifyOnSubscription(this, topic); + subscribe(topic, (L)myDefaultHandler); } public void setDefaultHandler(MessageHandler handler) { diff --git a/platform/util/src/com/intellij/util/messages/impl/MessageBusImpl.java b/platform/util/src/com/intellij/util/messages/impl/MessageBusImpl.java index 98a732c49eaa..16e35551f9ba 100644 --- a/platform/util/src/com/intellij/util/messages/impl/MessageBusImpl.java +++ b/platform/util/src/com/intellij/util/messages/impl/MessageBusImpl.java @@ -64,7 +64,7 @@ public class MessageBusImpl implements MessageBus { } public MessageBusImpl(final Object owner, MessageBus parentBus) { - myOwner = owner; + myOwner = owner == null ? null : owner.toString(); myParentBus = (MessageBusImpl)parentBus; if (myParentBus != null) { myParentBus.notifyChildBusCreated(this); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/statistics/VcsStatisticsPersistence.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/statistics/VcsStatisticsPersistence.java new file mode 100644 index 000000000000..0850d38c3749 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/statistics/VcsStatisticsPersistence.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2010 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.openapi.vcs.statistics; + +import com.intellij.openapi.project.Project; +import com.intellij.statistic.beans.UsageDescriptor; +import com.intellij.util.containers.HashMap; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.Set; + +public abstract class VcsStatisticsPersistence { + private Map> myVcsUsagesMap = new HashMap>(); + + public VcsStatisticsPersistence() { + } + + public void persist(@NotNull Project project, @NotNull Set vcs) { + myVcsUsagesMap.put(project.getName(), vcs); + } + + @NotNull + public Map> getVcsUsageMap() { + return myVcsUsagesMap; + } + +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/statistics/VcsStatisticsPersistenceComponent.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/statistics/VcsStatisticsPersistenceComponent.java new file mode 100644 index 000000000000..3cff5584312c --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/statistics/VcsStatisticsPersistenceComponent.java @@ -0,0 +1,147 @@ +/* + * Copyright 2000-2010 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.openapi.vcs.statistics; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.project.ProjectManagerListener; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.statistic.beans.UsageDescriptor; +import com.intellij.util.Function; +import com.intellij.util.containers.HashSet; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@State( + name = "VcsUsages", + storages = { + @Storage( + id = "vcs", + file = "$APP_CONFIG$/vcs.usages.xml" + )} +) +//todo !!! register this ApplicationComponent !!!! +public class VcsStatisticsPersistenceComponent extends VcsStatisticsPersistence + implements ApplicationComponent, PersistentStateComponent { + private static final String TOKENIZER = ","; + + @NonNls private static final String PROJECT_TAG = "project"; + @NonNls private static final String PROJECT_ID_ATTR = "id"; + @NonNls private static final String USAGES_ATTR = "usages"; + + public VcsStatisticsPersistenceComponent() { + } + + public static VcsStatisticsPersistenceComponent getInstance() { + return ApplicationManager.getApplication().getComponent(VcsStatisticsPersistenceComponent.class); + } + + public void loadState(final Element element) { + List projectsList = element.getChildren(PROJECT_TAG); + for (Object project : projectsList) { + Element projectElement = (Element)project; + String projectId = projectElement.getAttributeValue(PROJECT_ID_ATTR); + String vcs = projectElement.getAttributeValue(USAGES_ATTR); + if (!StringUtil.isEmptyOrSpaces(projectId) && !StringUtil.isEmptyOrSpaces(vcs)) { + Set vcsDescriptors = new HashSet(); + for (String key : StringUtil.split(vcs, TOKENIZER)) { + vcsDescriptors.add(new UsageDescriptor(VcsUsagesCollector.getGroupId(), key, 1)); + } + getVcsUsageMap().put(projectId, vcsDescriptors); + } + } + } + + public Element getState() { + Element element = new Element("state"); + + for (Map.Entry> vcsUsageEntry : getVcsUsageMap().entrySet()) { + Element projectElement = new Element(PROJECT_TAG); + projectElement.setAttribute(PROJECT_ID_ATTR, vcsUsageEntry.getKey()); + projectElement.setAttribute(USAGES_ATTR, joinUsages(vcsUsageEntry.getValue())); + + element.addContent(projectElement); + } + + return element; + } + + private static String joinUsages(@NotNull Set usages) { + return StringUtil.join(usages, new Function() { + @Override + public String fun(UsageDescriptor usageDescriptor) { + return usageDescriptor.getKey(); + } + }, TOKENIZER); + } + + @NotNull + @NonNls + public File[] getExportFiles() { + return new File[]{PathManager.getOptionsFile("vcs.usages")}; + } + + @NotNull + public String getPresentableName() { + return "Vcs Usages"; + } + + @NonNls + @NotNull + public String getComponentName() { + return "VcsStatisticsPersistenceComponent"; + } + + public void initComponent() { + ProjectManager.getInstance().addProjectManagerListener(new ProjectManagerListener() { + @Override + public void projectOpened(Project project) { + } + + @Override + public boolean canCloseProject(Project project) { + return true; + } + + @Override + public void projectClosed(Project project) { + } + + @Override + public void projectClosing(Project project) { + if (project != null) { + VcsUsagesCollector.persistProjectUsages(project); + } + } + }); + } + + public void disposeComponent() { + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/statistics/VcsUsagesCollector.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/statistics/VcsUsagesCollector.java new file mode 100644 index 000000000000..b534312e3b82 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/statistics/VcsUsagesCollector.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2010 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.openapi.vcs.statistics; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.impl.VcsDescriptor; +import com.intellij.statistic.UsagesCollector; +import com.intellij.statistic.beans.GroupDescriptor; +import com.intellij.statistic.beans.UsageDescriptor; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.hash.HashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.Set; + +// todo !!! this "statistics.usagesCollector" extension !!! +public class VcsUsagesCollector extends UsagesCollector { + private static final String GROUP_ID = "vcs"; + + public static void persistProjectUsages(@NotNull Project project) { + persistProjectUsages(project, getProjectUsages(project)); + } + + public static void persistProjectUsages(@NotNull Project project, @NotNull Set usages) { + persistProjectUsages(project, usages, VcsStatisticsPersistenceComponent.getInstance()); + } + + public static void persistProjectUsages(@NotNull Project project, + @NotNull Set usages, + @NotNull VcsStatisticsPersistenceComponent persistence) { + persistence.persist(project, usages); + } + + @NotNull + public static Set getApplicationUsages() { + return getApplicationUsages(VcsStatisticsPersistenceComponent.getInstance()); + } + + @NotNull + public static Set getApplicationUsages(@NotNull final VcsStatisticsPersistenceComponent persistence) { + final Map vcsUsagesMap = new HashMap(); + + for (Set descriptors : persistence.getVcsUsageMap().values()) { + for (UsageDescriptor descriptor : descriptors) { + final String key = descriptor.getKey(); + final Integer count = vcsUsagesMap.get(key); + vcsUsagesMap.put(key, count == null ? 1 : count.intValue() + 1); + } + } + + return ContainerUtil.map2Set(vcsUsagesMap.entrySet(), new Function, UsageDescriptor>() { + @Override + public UsageDescriptor fun(Map.Entry vcsUsage) { + return new UsageDescriptor(getGroupId(), vcsUsage.getKey(), vcsUsage.getValue()); + } + }); + } + + public static GroupDescriptor getGroupId() { + return GroupDescriptor.create(GROUP_ID, GroupDescriptor.HIGHER_PRIORITY); + } + + @NotNull + public Set getUsages(@Nullable Project project) { + if (project != null) { + persistProjectUsages(project, getProjectUsages(project)); + } + + return getApplicationUsages(); + } + + public static Set getProjectUsages(@NotNull Project project) { + return ContainerUtil.map2Set(ProjectLevelVcsManager.getInstance(project).getAllVcss(), new Function() { + @Override + public UsageDescriptor fun(VcsDescriptor descriptor) { + return new UsageDescriptor(getGroupId(), descriptor.getName(), 1); + } + }); + } +} + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java index 4e54bcb542c3..27ed3f58f051 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java @@ -288,7 +288,7 @@ public class GroovyToJavaGenerator { } if (method instanceof GrConstructor) { - writeConstructor(text, (GrConstructor)method, aClass.isEnum()); + writeConstructor(text, (GrConstructor)method, aClass.isEnum(), true); continue; } @@ -305,7 +305,7 @@ public class GroovyToJavaGenerator { MethodSignature signature = MethodSignatureUtil.createMethodSignature(method.getName(), parameterTypes, method.getTypeParameters(), PsiSubstitutor.EMPTY); if (methodSignatures.add(signature)) { - writeMethod(text, method, parametersCopy); + writeMethod(text, method, parametersCopy, true); } PsiParameter parameter = parameters[i]; @@ -317,7 +317,7 @@ public class GroovyToJavaGenerator { else { MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY); if (methodSignatures.add(signature)) { - writeMethod(text, method, parameters); + writeMethod(text, method, parameters, true); } } } @@ -407,7 +407,7 @@ public class GroovyToJavaGenerator { if (block != null) { text.append("{\n"); for (PsiMethod method : block.getMethods()) { - writeMethod(text, method, method.getParameterList().getParameters()); + writeMethod(text, method, method.getParameterList().getParameters(), true); } text.append("}"); } @@ -434,9 +434,11 @@ public class GroovyToJavaGenerator { } } - private void writeConstructor(final StringBuffer text, final GrConstructor constructor, boolean isEnum) { - text.append("\n"); - text.append(" "); + private void writeConstructor(final StringBuffer text, final GrConstructor constructor, boolean isEnum, final boolean prefix) { + if (prefix) { + text.append("\n"); + text.append(" "); + } if (!isEnum) { text.append("public "); //writeMethodModifiers(text, constructor.getModifierList(), JAVA_MODIFIERS); @@ -562,15 +564,15 @@ public class GroovyToJavaGenerator { final GroovyToJavaGenerator generator = new GroovyToJavaGenerator(method.getProject(), null, Collections.emptyList()); final StringBuffer buffer = new StringBuffer(); if (method instanceof GrConstructor) { - generator.writeConstructor(buffer, (GrConstructor)method, false); + generator.writeConstructor(buffer, (GrConstructor)method, false, false); } else { - generator.writeMethod(buffer, method, method.getParameterList().getParameters()); + generator.writeMethod(buffer, method, method.getParameterList().getParameters(), false); } return buffer.toString(); } - private void writeMethod(StringBuffer text, PsiMethod method, final PsiParameter[] parameters) { + private void writeMethod(StringBuffer text, PsiMethod method, final PsiParameter[] parameters, final boolean prefix) { if (method == null) return; String name = method.getName(); if (!JavaPsiFacade.getInstance(method.getProject()).getNameHelper().isIdentifier(name)) @@ -580,8 +582,10 @@ public class GroovyToJavaGenerator { PsiModifierList modifierList = method.getModifierList(); - text.append("\n"); - text.append(" "); + if (prefix) { + text.append("\n"); + text.append(" "); + } writeMethodModifiers(text, modifierList, JAVA_MODIFIERS); if (method.hasTypeParameters()) { appendTypeParameters(text, method); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java index 67f34354b175..6868eca27dd8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java @@ -148,6 +148,13 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { catch (IOException e) { LOG.error(e); } + clearScriptCache(); + } + + private static void clearScriptCache() { + for (Project project : ProjectManager.getInstance().getOpenProjects()) { + project.putUserData(SCRIPTS_CACHE, null); + } } static void disableFile(final VirtualFile vfile) { @@ -158,9 +165,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { LOG.error(e1); } vfile.putUserData(CACHED_EXECUTOR, null); - for (Project project : ProjectManager.getInstance().getOpenProjects()) { - project.putUserData(SCRIPTS_CACHE, null); - } + clearScriptCache(); } diff --git a/plugins/tasks/jira-connector/src/main/java/com/intellij/tasks/jira/JiraRepository.java b/plugins/tasks/jira-connector/src/main/java/com/intellij/tasks/jira/JiraRepository.java index c7a8540c6a4b..1ed71cd9f9bf 100644 --- a/plugins/tasks/jira-connector/src/main/java/com/intellij/tasks/jira/JiraRepository.java +++ b/plugins/tasks/jira-connector/src/main/java/com/intellij/tasks/jira/JiraRepository.java @@ -56,31 +56,25 @@ public class JiraRepository extends BaseRepositoryImpl implements XmlRpcTranspor super(type); } - public Task[] getIssues(String request, int max, long since) { - try { - StringBuilder url = new StringBuilder(getUrl()); - String version = getServerVersion(); - if (version == null || StringUtil.compareVersionNumbers(myServerVersion, "3.7") < 0) { - url.append("/secure/IssueNavigator.jspa?view=rss&decorator=none&"); - } - else { - url.append("/sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml?"); - } - url.append("tempMax=").append(max); - url.append("&assignee=").append(encodeUrl(getUsername())); + public Task[] getIssues(String request, int max, long since) throws Exception { + StringBuilder url = new StringBuilder(getUrl()); + String version = getServerVersion(); + if (version == null || StringUtil.compareVersionNumbers(myServerVersion, "3.7") < 0) { + url.append("/secure/IssueNavigator.jspa?view=rss&decorator=none&"); + } + else { + url.append("/sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml?"); + } + url.append("tempMax=").append(max); + url.append("&assignee=").append(encodeUrl(getUsername())); // url.append("&resolution=-1"); - url.append("&reset=true"); - url.append("&sorter/field=").append("updated"); - url.append("&sorter/order=").append("DESC"); - url.append("&pager/start=").append(0); - appendAuthentication(url, false); + url.append("&reset=true"); + url.append("&sorter/field=").append("updated"); + url.append("&sorter/order=").append("DESC"); + url.append("&pager/start=").append(0); + appendAuthentication(url, false); - return processRSS(url.toString()); - } - catch (Exception e) { - LOG.info(e); - return new Task[0]; - } + return processRSS(url.toString()); } @Override @@ -160,15 +154,19 @@ public class JiraRepository extends BaseRepositoryImpl implements XmlRpcTranspor } } - private String getServerVersion() { + private String getServerVersion() throws Exception { if (myServerVersion == null) { try { Map map = (Map)doXmlRpcRequest("getServerInfo"); myServerVersion = (String)map.get("version"); } catch (Exception e) { + myServerVersion = "3.8"; LOG.warn(e); + if (e.getMessage().contains("Authentication")) { + throw e; + } } } return myServerVersion; diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskManager.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskManager.java index b6f71294efe1..9139b7b85bcb 100644 --- a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskManager.java +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskManager.java @@ -32,8 +32,19 @@ public abstract class TaskManager { return project.getComponent(TaskManager.class); } + /** + * Queries all configured task repositories. + * Operation may be blocked for a while. + * @param query text search + * @return up-to-date issues retrieved from repositories + * @see #getCachedIssues() + */ public abstract List getIssues(String query); + /** + * Returns already cached issues. + * @return cached issues. + */ public abstract List getCachedIssues(); @Nullable @@ -53,7 +64,7 @@ public abstract class TaskManager { /** * Update issue cache asynchronously - * @param onComplete + * @param onComplete callback to be invoked after updating */ public abstract void updateIssues(@Nullable Runnable onComplete); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskSearchSupport.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskSearchSupport.java index 7ef4b52150bc..6004e8725dd4 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskSearchSupport.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskSearchSupport.java @@ -90,18 +90,14 @@ public class TaskSearchSupport { } private List getTasks(String pattern, boolean cached) { - List issues; - if (cached) { - issues = myManager.getCachedIssues(); + Set taskSet = new HashSet(myManager.getCachedIssues()); + if (!cached) { + taskSet.addAll(myManager.getIssues(pattern)); } - else { - issues = myManager.getIssues(pattern); - } - Set taskSet = new HashSet(issues); if (myRemoveLocal) { taskSet.removeAll(Arrays.asList(myManager.getLocalTasks())); } - issues = new ArrayList(taskSet); + List issues = new ArrayList(taskSet); Collections.sort(issues, myTaskComparator); return issues; } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java index 3cb677729135..770f88d9c034 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java @@ -1,8 +1,10 @@ package com.intellij.tasks.impl; +import com.intellij.notification.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; @@ -14,11 +16,13 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.changes.*; import com.intellij.tasks.*; +import com.intellij.tasks.config.TaskRepositoriesConfigurable; import com.intellij.tasks.context.WorkingContextManager; import com.intellij.ui.ColoredTreeCellRenderer; +import com.intellij.util.ArrayUtil; import com.intellij.util.EventDispatcher; import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.*; import com.intellij.util.xmlb.XmlSerializationException; import com.intellij.util.xmlb.XmlSerializer; import com.intellij.util.xmlb.XmlSerializerUtil; @@ -30,10 +34,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.Timer; +import javax.swing.event.HyperlinkEvent; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DecimalFormat; import java.util.*; +import java.util.HashMap; +import java.util.HashSet; /** @@ -57,12 +64,19 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe return i == 0 ? Comparing.compare(o2.getCreated(), o1.getCreated()) : i; } }; + private static final Convertor KEY_CONVERTOR = new Convertor() { + @Override + public String convert(Task o) { + return o.getId(); + } + }; private final Project myProject; private final WorkingContextManager myContextManager; private final Map myIssueCache = Collections.synchronizedMap(new HashMap()); + private final Map myTemporaryCache = Collections.synchronizedMap(new HashMap()); private final Map myTasks = Collections.synchronizedMap(new LinkedHashMap() { @Override @@ -93,6 +107,7 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe private final List myRepositories = new ArrayList(); private final EventDispatcher myDispatcher = EventDispatcher.create(TaskListener.class); + private Set myBadRepositories = new HashSet(); public TaskManagerImpl(Project project, WorkingContextManager contextManager, @@ -158,6 +173,12 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe public void setRepositories(List repositories) { + Set set = new HashSet(myRepositories); + set.removeAll(repositories); + myBadRepositories.removeAll(set); // remove all changed reps + myIssueCache.clear(); + myTemporaryCache.clear(); + myRepositories.clear(); myRepositories.addAll(repositories); @@ -202,19 +223,20 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe @Override public List getIssues(String query) { - if (myConfig.updateEnabled) { - synchronized (myIssueCache) { - return new ArrayList(myIssueCache.values()); - } - } else { - return getIssuesFromRepositories(query, 50, 0); + List tasks = getIssuesFromRepositories(query, 50, 0); + synchronized (myIssueCache) { + myTemporaryCache.clear(); + myTemporaryCache.putAll(ContainerUtil.assignKeys(tasks.iterator(), KEY_CONVERTOR)); } + return tasks; } @Override public List getCachedIssues() { synchronized (myIssueCache) { - return new ArrayList(myIssueCache.values()); + ArrayList tasks = new ArrayList(myIssueCache.values()); + tasks.addAll(myTemporaryCache.values()); + return tasks; } } @@ -586,9 +608,7 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe synchronized (myIssueCache) { myIssueCache.clear(); - for (Task issue : issues) { - myIssueCache.put(issue.getId(), issue); - } + myIssueCache.putAll(ContainerUtil.assignKeys(issues.iterator(), KEY_CONVERTOR)); } // update local tasks synchronized (myTasks) { @@ -617,8 +637,8 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe private List getIssuesFromRepositories(String request, int max, long since) { List issues = new ArrayList(); - for (TaskRepository repository : getAllRepositories()) { - if (!repository.isConfigured()) { + for (final TaskRepository repository : getAllRepositories()) { + if (!repository.isConfigured() || myBadRepositories.contains(repository)) { continue; } try { @@ -626,7 +646,20 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe ContainerUtil.addAll(issues, tasks); } catch (Exception e) { + myBadRepositories.add(repository); LOG.warn(e); + ApplicationManager.getApplication().getMessageBus().syncPublisher(Notifications.TOPIC).notify( + new Notification("Tasks", "Cannot connect to " + repository.getUrl(), + "

Configure server...

", NotificationType.WARNING, + new NotificationListener() { + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + TaskRepositoriesConfigurable configurable = new TaskRepositoriesConfigurable(myProject); + ShowSettingsUtil.getInstance().editConfigurable(myProject, configurable); + if (!ArrayUtil.contains(repository, getAllRepositories())) { + notification.expire(); + } + } + }), NotificationDisplayType.STICKY_BALLOON); } } return issues; diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/TaskCompletionTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/TaskCompletionTest.java index 0336cf4f4860..5a891420757f 100644 --- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/TaskCompletionTest.java +++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/TaskCompletionTest.java @@ -1,6 +1,9 @@ package com.intellij.tasks; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.psi.PsiFile; +import com.intellij.tasks.impl.LocalTaskImpl; import com.intellij.tasks.impl.TaskCompletionContributor; import com.intellij.tasks.impl.TaskManagerImpl; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; @@ -24,17 +27,33 @@ public class TaskCompletionTest extends LightCodeInsightFixtureTestCase { doTest("my TEST-", "my TEST-001: Test task"); } + public void testNumberCompletion() throws Exception { + configureFile("TEST-0"); + configureRepository(new LocalTaskImpl("TEST-001", "Test task"), new LocalTaskImpl("TEST-002", "Test task 2")); + LookupElement[] elements = myFixture.complete(CompletionType.BASIC); + assertNotNull(elements); + assertEquals(2, elements.length); + } + public void testSIOOBE() throws Exception { - doTest(" my ", " TEST-001: Test task my"); + doTest(" my", " TEST-001: Test task my"); } private void doTest(String text, String after) { - PsiFile psiFile = myFixture.configureByText("test.txt", text); - TaskCompletionContributor.installCompletion(myFixture.getDocument(psiFile), getProject(), null, false); - TaskManagerImpl manager = (TaskManagerImpl)TaskManager.getManager(getProject()); - manager.setRepositories(Arrays.asList(new TestRepository())); - manager.getState().updateEnabled = false; + configureFile(text); + configureRepository(new LocalTaskImpl("TEST-001", "Test task")); myFixture.completeBasic(); myFixture.checkResult(after); } + + private void configureFile(String text) { + PsiFile psiFile = myFixture.configureByText("test.txt", text); + TaskCompletionContributor.installCompletion(myFixture.getDocument(psiFile), getProject(), null, false); + } + + private void configureRepository(LocalTaskImpl... tasks) { + TaskManagerImpl manager = (TaskManagerImpl)TaskManager.getManager(getProject()); + manager.setRepositories(Arrays.asList(new TestRepository(tasks))); + manager.getState().updateEnabled = false; + } } diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/TestRepository.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/TestRepository.java index 807dca75e884..a4fd7d0913ea 100644 --- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/TestRepository.java +++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/TestRepository.java @@ -1,13 +1,18 @@ package com.intellij.tasks; import com.intellij.tasks.impl.BaseRepository; -import com.intellij.tasks.impl.LocalTaskImpl; import org.jetbrains.annotations.Nullable; /** * @author Dmitry Avdeev */ class TestRepository extends BaseRepository { + private final Task[] myTasks; + + public TestRepository(Task... tasks) { + myTasks = tasks; + } + @Override public BaseRepository clone() { return this; @@ -19,7 +24,7 @@ class TestRepository extends BaseRepository { @Override public Task[] getIssues(@Nullable String query, int max, long since) throws Exception { - return new Task[] { new LocalTaskImpl("TEST-001", "Test task")}; + return myTasks; } @Override diff --git a/plugins/testng/src/com/theoryinpractice/testng/inspection/ConvertAnnotationInspection.java b/plugins/testng/src/com/theoryinpractice/testng/inspection/ConvertAnnotationInspection.java index e9c95136cc5c..e3ad57c3d889 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/inspection/ConvertAnnotationInspection.java +++ b/plugins/testng/src/com/theoryinpractice/testng/inspection/ConvertAnnotationInspection.java @@ -92,7 +92,7 @@ public class ConvertAnnotationInspection extends BaseJavaLocalInspectionTool { final PsiElementFactory factory = JavaPsiFacade.getInstance(element.getProject()).getElementFactory(); PsiDocComment docComment = ((PsiDocCommentOwner)element).getDocComment(); if (docComment == null) { - docComment = factory.createDocCommentFromText("/**\n */", element); + docComment = factory.createDocCommentFromText("/**\n */"); docComment = (PsiDocComment)element.addBefore(docComment, parent); } @NonNls StringBuffer text = new StringBuffer(convertAnnotationClassToJavadocElement(annotation.getQualifiedName())); @@ -114,7 +114,7 @@ public class ConvertAnnotationInspection extends BaseJavaLocalInspectionTool { text.append(parameterText); text.append('\"'); } - docComment.addAfter(factory.createDocTagFromText('@' + text.toString(), element), docComment.getFirstChild()); + docComment.addAfter(factory.createDocTagFromText('@' + text.toString()), docComment.getFirstChild()); annotation.delete(); } catch (IncorrectOperationException e) { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/GuiDesignerConfigurable.java b/plugins/ui-designer/src/com/intellij/uiDesigner/GuiDesignerConfigurable.java index 17d3eb4dc3e4..4a21256dfc9c 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/GuiDesignerConfigurable.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/GuiDesignerConfigurable.java @@ -80,6 +80,10 @@ public final class GuiDesignerConfigurable implements SearchableConfigurable { public boolean isModified() { final GuiDesignerConfiguration configuration = GuiDesignerConfiguration.getInstance(myProject); + if (myGeneralUI == null) { + return false; + } + if (myGeneralUI.myChkCopyFormsRuntime.isSelected() != configuration.COPY_FORMS_RUNTIME_TO_OUTPUT) { return true; } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java index d48c3bb39441..e5176107d6bf 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java @@ -203,7 +203,10 @@ public class UIDesignerToolWindowManager implements ProjectComponent { } public void updateComponentTree() { - myComponentTreeBuilder.updateFromRoot(); + final ComponentTreeBuilder builder = myComponentTreeBuilder; + if (builder != null) { + builder.queueUpdate(); + } } public void addComponentSelectionListener(TreeSelectionListener treeSelectionListener) { diff --git a/xml/dom-openapi/src/com/intellij/codeInsight/navigation/NavigationGutterIconBuilder.java b/xml/dom-openapi/src/com/intellij/codeInsight/navigation/NavigationGutterIconBuilder.java index 93fea8af882c..0fa0015bd239 100644 --- a/xml/dom-openapi/src/com/intellij/codeInsight/navigation/NavigationGutterIconBuilder.java +++ b/xml/dom-openapi/src/com/intellij/codeInsight/navigation/NavigationGutterIconBuilder.java @@ -162,7 +162,7 @@ public class NavigationGutterIconBuilder { renderer.getIcon(), Pass.UPDATE_OVERRIDEN_MARKERS, tooltip == null ? null : new ConstantFunction(tooltip), - renderer, + renderer.isNavigateAction()? renderer : null, renderer.getAlignment()); } @@ -185,9 +185,7 @@ public class NavigationGutterIconBuilder { } }; - if (!myLazy) { - pointers.getValue(); - } + final boolean empty = !myLazy && pointers.getValue().isEmpty(); if (myTooltipText == null && !myLazy) { final SortedSet names = new TreeSet(); @@ -212,19 +210,31 @@ public class NavigationGutterIconBuilder { myCellRenderer = new DefaultPsiElementCellRenderer(); } - return new MyNavigationGutterIconRenderer(this, myAlignment, myIcon, myTooltipText, pointers); + return new MyNavigationGutterIconRenderer(this, myAlignment, myIcon, myTooltipText, pointers, empty); } private static class MyNavigationGutterIconRenderer extends NavigationGutterIconRenderer { private final Alignment myAlignment; private final Icon myIcon; private final String myTooltipText; + private final boolean myEmpty; - public MyNavigationGutterIconRenderer(final NavigationGutterIconBuilder builder, final Alignment alignment, final Icon icon, final String tooltipText, final NotNullLazyValue> pointers) { + public MyNavigationGutterIconRenderer(final NavigationGutterIconBuilder builder, + final Alignment alignment, + final Icon icon, + final String tooltipText, + final NotNullLazyValue> pointers, + boolean empty) { super(builder.myPopupTitle, builder.myEmptyText, builder.myCellRenderer, pointers); myAlignment = alignment; myIcon = icon; myTooltipText = tooltipText; + myEmpty = empty; + } + + @Override + public boolean isNavigateAction() { + return !myEmpty; } @NotNull diff --git a/xml/impl/src/com/intellij/xml/XmlExtension.java b/xml/impl/src/com/intellij/xml/XmlExtension.java index 761c649d37a1..24e98a544684 100644 --- a/xml/impl/src/com/intellij/xml/XmlExtension.java +++ b/xml/impl/src/com/intellij/xml/XmlExtension.java @@ -49,7 +49,6 @@ import java.util.Set; * @author Dmitry Avdeev */ public abstract class XmlExtension { - private static final ExtensionPointName EP_NAME = new ExtensionPointName("com.intellij.xml.xmlExtension"); public static final XmlExtension DEFAULT_EXTENSION = new DefaultXmlExtension(); diff --git a/xml/openapi/src/com/intellij/xml/XmlSchemaProvider.java b/xml/openapi/src/com/intellij/xml/XmlSchemaProvider.java index 7fa5b7b3e19e..0735d0061ee5 100644 --- a/xml/openapi/src/com/intellij/xml/XmlSchemaProvider.java +++ b/xml/openapi/src/com/intellij/xml/XmlSchemaProvider.java @@ -20,7 +20,6 @@ import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; -import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiDirectory; @@ -39,8 +38,7 @@ import java.util.Set; * @author Dmitry Avdeev */ public abstract class XmlSchemaProvider { - - public final static ExtensionPointName EP_NAME = new ExtensionPointName("com.intellij.xml.schemaProvider"); + public static final ExtensionPointName EP_NAME = new ExtensionPointName("com.intellij.xml.schemaProvider"); @Nullable public static XmlFile findSchema(@NotNull @NonNls String namespace, @Nullable Module module, @NotNull PsiFile file) { @@ -74,7 +72,7 @@ public abstract class XmlSchemaProvider { */ @Deprecated @Nullable - public static XmlSchemaProvider getAvailableProvider(final @NotNull XmlFile file) { + public static XmlSchemaProvider getAvailableProvider(@NotNull final XmlFile file) { for (XmlSchemaProvider provider: Extensions.getExtensions(EP_NAME)) { if (provider.isAvailable(file)) { return provider; @@ -83,7 +81,7 @@ public abstract class XmlSchemaProvider { return null; } - public static List getAvailableProviders(final @NotNull XmlFile file) { + public static List getAvailableProviders(@NotNull final XmlFile file) { return ContainerUtil.findAll(Extensions.getExtensions(EP_NAME), new Condition() { public boolean value(XmlSchemaProvider xmlSchemaProvider) { return xmlSchemaProvider.isAvailable(file); @@ -95,7 +93,7 @@ public abstract class XmlSchemaProvider { public abstract XmlFile getSchema(@NotNull @NonNls String url, @Nullable Module module, @NotNull final PsiFile baseFile); - public boolean isAvailable(final @NotNull XmlFile file) { + public boolean isAvailable(@NotNull final XmlFile file) { return false; } @@ -106,7 +104,7 @@ public abstract class XmlSchemaProvider { * @return available namespace uris, or null if the provider did not recognize the file. */ @NotNull - public Set getAvailableNamespaces(final @NotNull XmlFile file, final @Nullable String tagName) { + public Set getAvailableNamespaces(@NotNull final XmlFile file, @Nullable final String tagName) { return Collections.emptySet(); }