From 9805cfad680ea4b4e38326e73578b164d122d5d6 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Thu, 14 Jan 2016 13:51:39 +0300 Subject: [PATCH 01/25] javadoc for TemplatePreprocessor --- .../template/impl/TemplatePreprocessor.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplatePreprocessor.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplatePreprocessor.java index 0bc04d7dc6c0..32bd89489b6b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplatePreprocessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplatePreprocessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -16,12 +16,18 @@ package com.intellij.codeInsight.template.impl; -import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.psi.PsiFile; /** - * @author yole + * When an template is started, allows to prepare the editor before actual template expanding. + * + * For example, for some XML-based languages it make sense to check whether text of template contains + * unescaped character and insert CDATA-element to the editor before template expanding. + * + * @see TemplateOptionalProcessor + * @see com.intellij.codeInsight.template.TemplateSubstitutor */ public interface TemplatePreprocessor { ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.liveTemplatePreprocessor"); From 71e61af2ffb061c933198846f2de8576bb31b27f Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Thu, 14 Jan 2016 13:56:04 +0300 Subject: [PATCH 02/25] IDEA-80778 recollapse fold regions, expanded previously, when iterating over find results in editor --- .../find/impl/livePreview/SelectionManager.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java index 50f37927c506..a0b9714c12f6 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -21,8 +21,12 @@ import com.intellij.openapi.editor.*; import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + public class SelectionManager { @NotNull private final SearchResults mySearchResults; + private final List myRegionsToRestore = new ArrayList(); public SelectionManager(@NotNull SearchResults results) { mySearchResults = results; @@ -45,10 +49,17 @@ public class SelectionManager { foldingModel.runBatchFoldingOperation(new Runnable() { @Override public void run() { + for (FoldRegion region : myRegionsToRestore) { + if (region.isValid()) region.setExpanded(false); + } + myRegionsToRestore.clear(); for (FoldRegion region : allRegions) { if (!region.isValid()) continue; if (cursor.intersects(TextRange.create(region))) { - region.setExpanded(true); + if (!region.isExpanded()) { + region.setExpanded(true); + myRegionsToRestore.add(region); + } } } } From 9007fe6695d4e659d5bf9d3f4ef331a0f86d7d71 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 13 Jan 2016 14:02:37 +0300 Subject: [PATCH 03/25] lst: recalculate ranges on error --- .../com/intellij/openapi/vcs/ex/LineStatusTracker.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 9177842c6680..03afa30f617c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -405,8 +405,14 @@ public class LineStatusTracker { synchronized (myLock) { if (!myInitialized || myReleased || myBulkUpdate || myDuringRollback || myAnathemaThrown) return; if (myDirtyRange != null) { - doUpdateRanges(myDirtyRange.line1, myDirtyRange.line2, myDirtyRange.lineShift, myDirtyRange.beforeTotalLines); - myDirtyRange = null; + try { + doUpdateRanges(myDirtyRange.line1, myDirtyRange.line2, myDirtyRange.lineShift, myDirtyRange.beforeTotalLines); + myDirtyRange = null; + } + catch (Exception e) { + LOG.error(e); + reinstallRanges(); + } } } } From d7565314af49b4d3f116059b7c793e831d1c252f Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 13 Jan 2016 14:18:18 +0300 Subject: [PATCH 04/25] lst: check passed line range bounds --- .../src/com/intellij/diff/util/DiffUtil.java | 21 ++++++ .../openapi/vcs/ex/DocumentWrapper.java | 66 ------------------- .../openapi/vcs/ex/LineStatusTracker.java | 4 +- .../openapi/vcs/ex/RangesBuilder.java | 3 +- 4 files changed, 25 insertions(+), 69 deletions(-) delete mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java index d7c9affaeff6..bb1f9b7aa893 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java @@ -782,6 +782,27 @@ public class DiffUtil { return Math.max(document.getLineCount(), 1); } + @NotNull + public static List getLines(@NotNull Document document) { + return getLines(document, 0, getLineCount(document)); + } + + @NotNull + public static List getLines(@NotNull Document document, int startLine, int endLine) { + if (startLine < 0 || startLine > endLine || endLine > getLineCount(document)) { + throw new IndexOutOfBoundsException(String.format("Wrong line range: [%d, %d); lineCount: '%d'", + startLine, endLine, document.getLineCount())); + } + + List result = new ArrayList(); + for (int i = startLine; i < endLine; i++) { + int start = document.getLineStartOffset(i); + int end = document.getLineEndOffset(i); + result.add(document.getText(new TextRange(start, end))); + } + return result; + } + // // Updating ranges on change // diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java deleted file mode 100644 index 1674b55ff3b6..000000000000 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2000-2009 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.ex; - -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.util.TextRange; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; - -/** - * author: lesya - */ -public class DocumentWrapper { - private final Document myDocument; - - public DocumentWrapper(@NotNull Document document) { - myDocument = document; - } - - public int getLineNum(int offset) { - return myDocument.getLineNumber(offset); - } - - @NotNull - public List getLines() { - return getLines(0, getLineCount(myDocument) - 1); - } - - @NotNull - public List getLines(int from, int to) { - ArrayList result = new ArrayList(); - for (int i = from; i <= to; i++) { - result.add(getLine(i)); - } - return result; - } - - @NotNull - private String getLine(final int i) { - TextRange range = new TextRange(myDocument.getLineStartOffset(i), myDocument.getLineEndOffset(i)); - if (range.getLength() < 0) { - assert false : myDocument; - } - return myDocument.getText(range); - } - - private static int getLineCount(@NotNull Document document) { - return Math.max(document.getLineCount(), 1); - } -} - diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 03afa30f617c..4e66b5627148 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -628,8 +628,8 @@ public class LineStatusTracker { return Collections.singletonList(new Range(changedLine1, changedLine2, vcsLine1, vcsLine2)); } - List lines = new DocumentWrapper(myDocument).getLines(changedLine1, changedLine2 - 1); - List vcsLines = new DocumentWrapper(myVcsDocument).getLines(vcsLine1, vcsLine2 - 1); + List lines = DiffUtil.getLines(myDocument, changedLine1, changedLine2); + List vcsLines = DiffUtil.getLines(myVcsDocument, vcsLine1, vcsLine2); return new RangesBuilder(lines, vcsLines, changedLine1, vcsLine1, myMode).getRanges(); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java index 6b795a294873..18202a0a6d46 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs.ex; +import com.intellij.diff.util.DiffUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.text.StringUtil; @@ -46,7 +47,7 @@ public class RangesBuilder { @NotNull Document vcs, @NotNull LineStatusTracker.Mode mode) throws FilesTooBigForDiffException { - this(new DocumentWrapper(current).getLines(), new DocumentWrapper(vcs).getLines(), 0, 0, mode); + this(DiffUtil.getLines(current), DiffUtil.getLines(vcs), 0, 0, mode); } public RangesBuilder(@NotNull List current, From 3d8ecff7e8391aa8977e4dd56bd46c43f8c52484 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 13 Jan 2016 14:51:12 +0300 Subject: [PATCH 05/25] lst: make RangesBuilder stateless --- .../VcsAwareFormatChangedTextUtil.java | 2 +- .../openapi/vcs/ex/LineStatusTracker.java | 4 +- .../openapi/vcs/ex/RangesBuilder.java | 79 +++++-------------- 3 files changed, 23 insertions(+), 62 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/codeInsight/actions/VcsAwareFormatChangedTextUtil.java b/platform/vcs-impl/src/com/intellij/codeInsight/actions/VcsAwareFormatChangedTextUtil.java index 08bf464035da..da1a77e3c279 100644 --- a/platform/vcs-impl/src/com/intellij/codeInsight/actions/VcsAwareFormatChangedTextUtil.java +++ b/platform/vcs-impl/src/com/intellij/codeInsight/actions/VcsAwareFormatChangedTextUtil.java @@ -113,7 +113,7 @@ class VcsAwareFormatChangedTextUtil extends FormatChangedTextUtil { @NotNull CharSequence contentFromVcs) throws FilesTooBigForDiffException { Document documentFromVcs = ((EditorFactoryImpl)EditorFactory.getInstance()).createDocument(contentFromVcs, true, false); - return new RangesBuilder(document, documentFromVcs).getRanges(); + return RangesBuilder.createRanges(document, documentFromVcs); } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 4e66b5627148..d40546df0d85 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -152,7 +152,7 @@ public class LineStatusTracker { destroyRanges(); try { - myRanges = new RangesBuilder(myDocument, myVcsDocument, myMode).getRanges(); + myRanges = RangesBuilder.createRanges(myDocument, myVcsDocument, myMode == Mode.SMART); for (final Range range : myRanges) { createHighlighter(range); } @@ -631,7 +631,7 @@ public class LineStatusTracker { List lines = DiffUtil.getLines(myDocument, changedLine1, changedLine2); List vcsLines = DiffUtil.getLines(myVcsDocument, vcsLine1, vcsLine2); - return new RangesBuilder(lines, vcsLines, changedLine1, vcsLine1, myMode).getRanges(); + return RangesBuilder.createRanges(lines, vcsLines, changedLine1, vcsLine1, myMode == Mode.SMART); } private static void shiftRanges(@NotNull List rangesAfterChange, int shift) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java index 18202a0a6d46..56d7ca2449ee 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java @@ -26,80 +26,41 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedList; import java.util.List; -/** - * author: lesya - */ - public class RangesBuilder { private static final Logger LOG = Logger.getInstance(RangesBuilder.class); - @NotNull private final List myRanges; - - public RangesBuilder(@NotNull Document current, - @NotNull Document vcs) throws FilesTooBigForDiffException { - this(current, vcs, LineStatusTracker.Mode.DEFAULT); - } - - public RangesBuilder(@NotNull Document current, - @NotNull Document vcs, - @NotNull LineStatusTracker.Mode mode) - throws FilesTooBigForDiffException { - this(DiffUtil.getLines(current), DiffUtil.getLines(vcs), 0, 0, mode); - } - - public RangesBuilder(@NotNull List current, - @NotNull List vcs, - int shift, - int vcsShift, - @NotNull LineStatusTracker.Mode mode) - throws FilesTooBigForDiffException { - myRanges = new LinkedList(); - - switch (mode) { - case DEFAULT: - case SILENT: - processDefault(current, vcs, shift, vcsShift); - break; - case SMART: - processSmart(current, vcs, shift, vcsShift); - break; - default: - throw new IllegalStateException(); - } + @NotNull + public static List createRanges(@NotNull Document current, @NotNull Document vcs) throws FilesTooBigForDiffException { + return createRanges(current, vcs, false); } @NotNull - public List getRanges() { - return myRanges; + public static List createRanges(@NotNull Document current, @NotNull Document vcs, boolean innerWhitespaceChanges) + throws FilesTooBigForDiffException { + return createRanges(DiffUtil.getLines(current), DiffUtil.getLines(vcs), 0, 0, innerWhitespaceChanges); } - private void processDefault(@NotNull List current, - @NotNull List vcs, - int shift, - int vcsShift) throws FilesTooBigForDiffException { + @NotNull + public static List createRanges(@NotNull List current, + @NotNull List vcs, + int shift, + int vcsShift, + boolean innerWhitespaceChanges) throws FilesTooBigForDiffException { Diff.Change ch = Diff.buildChanges(ArrayUtil.toStringArray(vcs), ArrayUtil.toStringArray(current)); + List result = new ArrayList(); while (ch != null) { - Range range = createOn(ch, shift, vcsShift); - myRanges.add(range); - ch = ch.link; - } - } - - private void processSmart(@NotNull List current, - @NotNull List vcs, - int shift, - int vcsShift) throws FilesTooBigForDiffException { - Diff.Change ch = Diff.buildChanges(ArrayUtil.toStringArray(vcs), ArrayUtil.toStringArray(current)); - - while (ch != null) { - Range range = createOnSmart(ch, shift, vcsShift, current, vcs); - myRanges.add(range); + if (innerWhitespaceChanges) { + result.add(createOnSmart(ch, shift, vcsShift, current, vcs)); + } + else { + result.add(createOn(ch, shift, vcsShift)); + } ch = ch.link; } + return result; } private static Range createOn(@NotNull Diff.Change change, int shift, int vcsShift) { From 9966e06c5488f58759ca516466d890179410ba30 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 11 Jan 2016 16:13:30 +0300 Subject: [PATCH 06/25] editor: better name for gutter area --- .../openapi/editor/impl/EditorGutterComponentImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 43d91537532b..2cba360d0cff 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -103,7 +103,7 @@ import java.util.List; *
    *
  • Left free painters
  • *
  • Icons
  • - *
  • Debugger additional area
  • + *
  • Gap (required by debugger to set breakpoints with mouse click - IDEA-137353)
  • *
  • Free painters
  • *
* @@ -1186,7 +1186,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse public int getLineMarkerAreaWidth() { return isLineMarkersShown() ? getLeftFreePaintersAreaWidth() + myIconsAreaWidth + - getDebuggerAdditionalAreaWidth() + getRightFreePaintersAreaWidth() : 0; + getGapAfterIconsArea() + getRightFreePaintersAreaWidth() : 0; } public void setLineNumberAreaWidthFunction(@NotNull TIntFunction calculator) { @@ -1276,7 +1276,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse @Override public int getLineMarkerFreePaintersAreaOffset() { - return getIconAreaOffset() + myIconsAreaWidth + getDebuggerAdditionalAreaWidth(); + return getIconAreaOffset() + myIconsAreaWidth + getGapAfterIconsArea(); } public int getLeftFreePaintersAreaWidth() { @@ -1292,7 +1292,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse return myIconsAreaWidth; } - public int getDebuggerAdditionalAreaWidth() { + public int getGapAfterIconsArea() { return isRealEditor() ? GAP_BETWEEN_AREAS : 0; } From fe28d3d31b510325876192ea5c25a52a6f249125 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 14 Jan 2016 12:15:41 +0100 Subject: [PATCH 07/25] [java] using "InnerClasses" attribute for resolving binary names in .class stubs (IDEA-82515) Previously, IDEA relied on heuristics to resolve binary names like "Map$Entry" into a source form ("Map.Entry"). The problem with this approach is that '$' is a legal part of Java identifiers. The fix (1) consolidates the heuristics from two different places into a single mapper, and (2) allows to use "InnerTables" attribute instead (according to JVMS 4.7.6, it should contain at least some of the referenced inner classes) - this part is disabled by default. --- .../impl/compiled/ClassFileStubBuilder.java | 8 +- .../psi/impl/compiled/SignatureParsing.java | 224 +++----- .../impl/compiled/StubBuildingVisitor.java | 495 ++++++++++-------- .../java/stubs/impl/PsiMethodStubImpl.java | 40 +- .../intellij/psi/SignatureParsingTest.java | 21 +- .../util/resources/misc/registry.properties | 5 + .../resolve/GroovyTraitFieldsFileIndex.java | 27 +- 7 files changed, 422 insertions(+), 398 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java index 89125f17034c..baec88c7997e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java @@ -38,7 +38,7 @@ import static com.intellij.psi.compiled.ClassFileDecompilers.Full; public class ClassFileStubBuilder implements BinaryFileStubBuilder { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.compiled.ClassFileStubBuilder"); - public static final int STUB_VERSION = 12; + public static final int STUB_VERSION = 13; @Override public boolean acceptsFile(@NotNull VirtualFile file) { @@ -59,7 +59,8 @@ public class ClassFileStubBuilder implements BinaryFileStubBuilder { } } catch (ClsFormatException e) { - LOG.debug(e); + if (LOG.isDebugEnabled()) LOG.debug(file.getPath(), e); + else LOG.info(file.getPath() + ": " + e.getMessage()); } try { @@ -70,7 +71,8 @@ public class ClassFileStubBuilder implements BinaryFileStubBuilder { return stub; } catch (ClsFormatException e) { - LOG.debug(e); + if (LOG.isDebugEnabled()) LOG.debug(file.getPath(), e); + else LOG.info(file.getPath() + ": " + e.getMessage()); } } finally { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/SignatureParsing.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/SignatureParsing.java index b4212b628fa8..215b50a65720 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/SignatureParsing.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/SignatureParsing.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -15,63 +15,60 @@ */ package com.intellij.psi.impl.compiled; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.CommonClassNames; -import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; -import com.intellij.psi.impl.java.stubs.PsiTypeParameterListStub; -import com.intellij.psi.impl.java.stubs.PsiTypeParameterStub; -import com.intellij.psi.impl.java.stubs.impl.PsiTypeParameterListStubImpl; -import com.intellij.psi.impl.java.stubs.impl.PsiTypeParameterStubImpl; -import com.intellij.psi.stubs.StubElement; import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; import com.intellij.util.cls.ClsFormatException; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.io.StringRef; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.text.CharacterIterator; +import java.util.Collections; import java.util.List; +import static com.intellij.openapi.util.Pair.pair; + /** * @author max */ public class SignatureParsing { private SignatureParsing() { } - public static PsiTypeParameterListStub parseTypeParametersDeclaration(CharacterIterator iterator, StubElement parentStub) throws ClsFormatException { - PsiTypeParameterListStub list = new PsiTypeParameterListStubImpl(parentStub); - - if (iterator.current() == '<') { - iterator.next(); - while (iterator.current() != '>') { - parseTypeParameter(iterator, list); - } - iterator.next(); + @NotNull + public static List> parseTypeParametersDeclaration(CharacterIterator signature, Function mapping) throws ClsFormatException { + if (signature.current() != '<') { + return Collections.emptyList(); } - return list; + List> typeParameters = ContainerUtil.newArrayList(); + signature.next(); + while (signature.current() != '>') { + typeParameters.add(parseTypeParameter(signature, mapping)); + } + signature.next(); + return typeParameters; } - private static PsiTypeParameterStub parseTypeParameter(CharacterIterator iterator, PsiTypeParameterListStub parent) throws ClsFormatException { + private static Pair parseTypeParameter(CharacterIterator signature, Function mapping) throws ClsFormatException { StringBuilder name = new StringBuilder(); - while (iterator.current() != ':' && iterator.current() != CharacterIterator.DONE) { - name.append(iterator.current()); - iterator.next(); + while (signature.current() != ':' && signature.current() != CharacterIterator.DONE) { + name.append(signature.current()); + signature.next(); } - if (iterator.current() == CharacterIterator.DONE) { + if (signature.current() == CharacterIterator.DONE) { throw new ClsFormatException(); } - - //todo parse annotations on type param - PsiTypeParameterStub parameterStub = new PsiTypeParameterStubImpl(parent, StringRef.fromString(name.toString())); + String parameterName = mapping.fun(name.toString()); // postpone list allocation till a second bound is seen; ignore sole Object bound List bounds = null; boolean jlo = false; - while (iterator.current() == ':') { - iterator.next(); - String bound = parseTopLevelClassRefSignature(iterator); + while (signature.current() == ':') { + signature.next(); + String bound = parseTopLevelClassRefSignature(signature, mapping); if (bound == null) continue; if (bounds == null) { if (CommonClassNames.JAVA_LANG_OBJECT.equals(bound)) { @@ -86,25 +83,25 @@ public class SignatureParsing { bounds.add(bound); } - StubBuildingVisitor.newReferenceList(JavaStubElementTypes.EXTENDS_BOUND_LIST, parameterStub, ArrayUtil.toStringArray(bounds)); - - return parameterStub; + return pair(parameterName, ArrayUtil.toStringArray(bounds)); } @Nullable - public static String parseTopLevelClassRefSignature(CharacterIterator signature) throws ClsFormatException { - if (signature.current() == 'L') { - return parseParameterizedClassRefSignature(signature); + public static String parseTopLevelClassRefSignature(CharacterIterator signature, Function mapping) throws ClsFormatException { + switch (signature.current()) { + case 'L': + return parseParameterizedClassRefSignature(signature, mapping); + case 'T': + return parseTypeVariableRefSignature(signature); + default: + return null; } - if (signature.current() == 'T') { - return parseTypeVariableRefSignature(signature); - } - return null; } private static String parseTypeVariableRefSignature(CharacterIterator signature) { - signature.next(); StringBuilder id = new StringBuilder(); + + signature.next(); while (signature.current() != ';' && signature.current() != '>') { id.append(signature.current()); signature.next(); @@ -117,50 +114,27 @@ public class SignatureParsing { return id.toString(); } - private static String parseParameterizedClassRefSignature(CharacterIterator signature) throws ClsFormatException { - assert signature.current() == 'L'; - + private static String parseParameterizedClassRefSignature(CharacterIterator signature, Function mapping) throws ClsFormatException { StringBuilder canonicalText = new StringBuilder(); + boolean mapped = false, firstArg; signature.next(); while (signature.current() != ';' && signature.current() != CharacterIterator.DONE) { - switch (signature.current()) { - case '$': - if (signature.getIndex() > 0) { - char previous = signature.previous(); - signature.next(); - boolean standAlone$ = !StringUtil.isJavaIdentifierPart(previous); // /$ - if (standAlone$) { - canonicalText.append('$'); - break; - } - else if (signature.getIndex() + 1 < signature.getEndIndex()) { - char next = signature.next(); - signature.previous(); - standAlone$ = !StringUtil.isJavaIdentifierPart(next); // $; - if (standAlone$) { - canonicalText.append('$'); - break; - } - } - } - case '/': - case '.': - canonicalText.append('.'); - break; - case '<': - canonicalText.append('<'); - signature.next(); - do { - processTypeArgument(signature, canonicalText); - } - while (signature.current() != '>'); - canonicalText.append('>'); - break; - case ' ': - break; - default: - canonicalText.append(signature.current()); + char c = signature.current(); + if (c == '<') { + canonicalText = new StringBuilder(mapping.fun(canonicalText.toString())); + mapped = true; + firstArg = true; + signature.next(); + do { + canonicalText.append(firstArg ? '<' : ',').append(parseClassOrTypeVariableElement(signature, mapping)); + firstArg = false; + } + while (signature.current() != '>'); + canonicalText.append('>'); + } + else if (c != ' ') { + canonicalText.append(c); } signature.next(); } @@ -168,53 +142,29 @@ public class SignatureParsing { if (signature.current() == CharacterIterator.DONE) { throw new ClsFormatException(); } - - for (int index = 0; index < canonicalText.length(); index++) { - final char c = canonicalText.charAt(index); - if ('0' <= c && c <= '1') { - if (index > 0 && canonicalText.charAt(index - 1) == '.') { - canonicalText.setCharAt(index - 1, '$'); - } - } - } - signature.next(); - return canonicalText.toString(); + String text = canonicalText.toString(); + if (!mapped) text = mapping.fun(text); + return text; } - private static void processTypeArgument(CharacterIterator signature, StringBuilder canonicalText) throws ClsFormatException { - String typeArgument = parseClassOrTypeVariableElement(signature); - canonicalText.append(typeArgument); - if (signature.current() != '>') { - canonicalText.append(','); - } - } - - public static String parseClassOrTypeVariableElement(CharacterIterator signature) throws ClsFormatException { + private static String parseClassOrTypeVariableElement(CharacterIterator signature, Function mapping) throws ClsFormatException { char variance = parseVariance(signature); if (variance == '*') { - return decorateTypeText("*", variance); + return decorateTypeText(null, variance); } - int arrayCount = 0; - while (signature.current() == '[') { - arrayCount++; - signature.next(); + int dimensions = parseDimensions(signature); + + String text = parseTypeWithoutVariance(signature, mapping); + if (text == null) throw new ClsFormatException(); + + if (dimensions > 0) { + text += StringUtil.repeat("[]", dimensions); } - final String type = parseTypeWithoutVariance(signature); - if (type != null) { - String ref = type; - while (arrayCount > 0) { - ref += "[]"; - arrayCount--; - } - return decorateTypeText(ref, variance); - } - else { - throw new ClsFormatException(); - } + return decorateTypeText(text, variance); } private static final char VARIANCE_NONE = '\0'; @@ -224,7 +174,7 @@ public class SignatureParsing { private static final String VARIANCE_EXTENDS_PREFIX = "? extends "; private static final String VARIANCE_SUPER_PREFIX = "? super "; - private static String decorateTypeText(final String canonical, final char variance) { + private static String decorateTypeText(String canonical, char variance) { switch (variance) { case VARIANCE_NONE: return canonical; @@ -256,39 +206,39 @@ public class SignatureParsing { default: variance = '\0'; } - return variance; } - @NotNull - public static String parseTypeString(@NotNull CharacterIterator signature) throws ClsFormatException { - int arrayDimensions = 0; + private static int parseDimensions(CharacterIterator signature) { + int dimensions = 0; while (signature.current() == '[') { - arrayDimensions++; + dimensions++; signature.next(); } + return dimensions; + } - char variance = parseVariance(signature); + @NotNull + public static String parseTypeString(CharacterIterator signature, Function mapping) throws ClsFormatException { + int dimensions = parseDimensions(signature); - String text = parseTypeWithoutVariance(signature); + String text = parseTypeWithoutVariance(signature, mapping); if (text == null) throw new ClsFormatException(); - for (int i = 0; i < arrayDimensions; i++) { - text += "[]"; - } - if (variance != '\0') { - text = variance + text; + if (dimensions > 0) { + text += StringUtil.repeat("[]", dimensions); } + return text; } @Nullable - private static String parseTypeWithoutVariance(final CharacterIterator signature) throws ClsFormatException { - final String text; - switch (signature.current()) { + private static String parseTypeWithoutVariance(CharacterIterator signature, Function mapping) throws ClsFormatException { + String text = null; + switch (signature.current()) { case 'L': - text = parseParameterizedClassRefSignature(signature); + text = parseParameterizedClassRefSignature(signature, mapping); break; case 'T': @@ -339,10 +289,8 @@ public class SignatureParsing { text = "void"; signature.next(); break; - - default: - return null; } + return text; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java index 464d8ed1e393..aae08dbc0565 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java @@ -15,7 +15,11 @@ */ package com.intellij.psi.impl.compiled; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.PsiNameHelper; import com.intellij.psi.PsiReferenceList; @@ -27,7 +31,10 @@ import com.intellij.psi.stubs.PsiFileStub; import com.intellij.psi.stubs.StubElement; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; +import com.intellij.util.Function; import com.intellij.util.cls.ClsFormatException; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.io.StringRef; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.org.objectweb.asm.*; @@ -35,10 +42,10 @@ import org.jetbrains.org.objectweb.asm.*; import java.lang.reflect.Array; import java.text.CharacterIterator; import java.text.StringCharacterIterator; -import java.util.ArrayList; import java.util.List; -import java.util.regex.Pattern; +import java.util.Map; +import static com.intellij.openapi.util.Pair.pair; import static com.intellij.psi.CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION; import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING; @@ -46,26 +53,27 @@ import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING; * @author max */ public class StubBuildingVisitor extends ClassVisitor { - private static final Pattern REGEX_PATTERN = Pattern.compile("(?<=[^\\$\\.])\\$(?=[^\\$])"); // disallow .$ or $$ + private static final Logger LOG = Logger.getInstance(StubBuildingVisitor.class); - public static final String DOUBLE_POSITIVE_INF = "1.0 / 0.0"; - public static final String DOUBLE_NEGATIVE_INF = "-1.0 / 0.0"; - public static final String DOUBLE_NAN = "0.0d / 0.0"; - - public static final String FLOAT_POSITIVE_INF = "1.0f / 0.0"; - public static final String FLOAT_NEGATIVE_INF = "-1.0f / 0.0"; - public static final String FLOAT_NAN = "0.0f / 0.0"; - - private static final int ASM_API = Opcodes.ASM5; + private static final boolean MAP_INNER_CLASSES_BY_TABLE = Registry.is("java.lib.inner.class.detection.by.table"); + private static final String DOUBLE_POSITIVE_INF = "1.0 / 0.0"; + private static final String DOUBLE_NEGATIVE_INF = "-1.0 / 0.0"; + private static final String DOUBLE_NAN = "0.0d / 0.0"; + private static final String FLOAT_POSITIVE_INF = "1.0f / 0.0"; + private static final String FLOAT_NEGATIVE_INF = "-1.0f / 0.0"; + private static final String FLOAT_NAN = "0.0f / 0.0"; private static final String SYNTHETIC_CLASS_INIT_METHOD = ""; private static final String SYNTHETIC_INIT_METHOD = ""; + private static final int ASM_API = Opcodes.ASM5; + private final T mySource; private final InnerClassSourceStrategy myInnersStrategy; private final StubElement myParent; private final int myAccess; private final String myShortName; + private final Function myMapping; private String myInternalName; private PsiClassStub myResult; private PsiModifierListStub myModList; @@ -77,6 +85,9 @@ public class StubBuildingVisitor extends ClassVisitor { myParent = parent; myAccess = access; myShortName = shortName; + + Map> mapping = loadMapping(classSource); + myMapping = mapping != null ? createMapping(mapping) : GUESSING_MAPPER; } public PsiClassStub getResult() { @@ -97,7 +108,6 @@ public class StubBuildingVisitor extends ClassVisitor { boolean isInterface = (flags & Opcodes.ACC_INTERFACE) != 0; boolean isEnum = (flags & Opcodes.ACC_ENUM) != 0; boolean isAnnotationType = (flags & Opcodes.ACC_ANNOTATION) != 0; - byte stubFlags = PsiClassStubImpl.packFlags(isDeprecated, isInterface, isEnum, false, false, isAnnotationType, false, false); myResult = new PsiClassStubImpl(JavaStubElementTypes.CLASS, myParent, fqn, shortName, null, stubFlags); @@ -107,66 +117,82 @@ public class StubBuildingVisitor extends ClassVisitor { myModList = new PsiModifierListStubImpl(myResult, packClassFlags(flags)); - CharacterIterator signatureIterator = signature != null ? new StringCharacterIterator(signature) : null; - if (signatureIterator != null) { + ClassInfo info = null; + if (signature != null) { try { - SignatureParsing.parseTypeParametersDeclaration(signatureIterator, myResult); - } - catch (ClsFormatException e) { - signatureIterator = null; + info = parseClassSignature(signature); } + catch (ClsFormatException e) { LOG.warn(signature, e); } } - else { - new PsiTypeParameterListStubImpl(myResult); + if (info == null) { + info = parseClassDescription(superName, interfaces); } - String convertedSuper; - List convertedInterfaces = new ArrayList(); - if (signatureIterator == null) { - convertedSuper = parseClassDescription(superName, interfaces, convertedInterfaces); - } - else { - try { - convertedSuper = parseClassSignature(signatureIterator, convertedInterfaces); - } - catch (ClsFormatException e) { - new PsiTypeParameterListStubImpl(myResult); - convertedSuper = parseClassDescription(superName, interfaces, convertedInterfaces); - } + PsiTypeParameterListStub typeParameterList = new PsiTypeParameterListStubImpl(myResult); + for (Pair parameter : info.typeParameters) { + PsiTypeParameterStub parameterStub = new PsiTypeParameterStubImpl(typeParameterList, StringRef.fromString(parameter.first)); + newReferenceList(JavaStubElementTypes.EXTENDS_BOUND_LIST, parameterStub, parameter.second); } - if (isInterface) { - if (isAnnotationType) { - convertedInterfaces.remove(JAVA_LANG_ANNOTATION_ANNOTATION); + if (myResult.isInterface()) { + if (info.interfaceNames != null && myResult.isAnnotationType()) { + info.interfaceNames.remove(JAVA_LANG_ANNOTATION_ANNOTATION); } - newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult, ArrayUtil.toStringArray(convertedInterfaces)); + newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult, ArrayUtil.toStringArray(info.interfaceNames)); newReferenceList(JavaStubElementTypes.IMPLEMENTS_LIST, myResult, ArrayUtil.EMPTY_STRING_ARRAY); } else { - if (convertedSuper == null || "java/lang/Object".equals(superName) || isEnum && "java/lang/Enum".equals(superName)) { + if (info.superName == null || "java/lang/Object".equals(superName) || myResult.isEnum() && "java/lang/Enum".equals(superName)) { newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult, ArrayUtil.EMPTY_STRING_ARRAY); } else { - newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult, new String[]{convertedSuper}); + newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult, new String[]{info.superName}); } - newReferenceList(JavaStubElementTypes.IMPLEMENTS_LIST, myResult, ArrayUtil.toStringArray(convertedInterfaces)); + newReferenceList(JavaStubElementTypes.IMPLEMENTS_LIST, myResult, ArrayUtil.toStringArray(info.interfaceNames)); } } - private static String getFqn(@NotNull String internalName, @Nullable String shortName, @Nullable String parentName) { + private String getFqn(@NotNull String internalName, @Nullable String shortName, @Nullable String parentName) { if (shortName == null || !internalName.endsWith(shortName)) { - return getClassName(internalName); + return myMapping.fun(internalName); } if (internalName.length() == shortName.length()) { return shortName; } if (parentName == null) { - parentName = getClassName(internalName.substring(0, internalName.length() - shortName.length() - 1)); + parentName = myMapping.fun(internalName.substring(0, internalName.length() - shortName.length() - 1)); } return parentName + '.' + shortName; } - public static void newReferenceList(JavaClassReferenceListElementType type, StubElement parent, String[] types) { + private ClassInfo parseClassSignature(String signature) throws ClsFormatException { + ClassInfo result = new ClassInfo(); + CharacterIterator iterator = new StringCharacterIterator(signature); + result.typeParameters = SignatureParsing.parseTypeParametersDeclaration(iterator, myMapping); + result.superName = SignatureParsing.parseTopLevelClassRefSignature(iterator, myMapping); + while (iterator.current() != CharacterIterator.DONE) { + String name = SignatureParsing.parseTopLevelClassRefSignature(iterator, myMapping); + if (name == null) throw new ClsFormatException(); + if (result.interfaceNames == null) result.interfaceNames = ContainerUtil.newSmartList(); + result.interfaceNames.add(name); + } + return result; + } + + private ClassInfo parseClassDescription(String superClass, String[] superInterfaces) { + ClassInfo result = new ClassInfo(); + result.typeParameters = ContainerUtil.emptyList(); + result.superName = superClass != null ? myMapping.fun(superClass) : null; + result.interfaceNames = superInterfaces == null ? null : ContainerUtil.map(superInterfaces, new Function() { + @Override + public String fun(String name) { + return myMapping.fun(name); + } + }); + return result; + } + + private static void newReferenceList(JavaClassReferenceListElementType type, StubElement parent, String[] types) { PsiReferenceList.Role role; if (type == JavaStubElementTypes.EXTENDS_LIST) role = PsiReferenceList.Role.EXTENDS_LIST; @@ -178,26 +204,6 @@ public class StubBuildingVisitor extends ClassVisitor { new PsiClassReferenceListStubImpl(type, parent, types, role); } - @Nullable - private static String parseClassDescription(String superName, String[] interfaces, List convertedInterfaces) { - String convertedSuper = superName != null ? getClassName(superName) : null; - for (String anInterface : interfaces) { - convertedInterfaces.add(getClassName(anInterface)); - } - return convertedSuper; - } - - @Nullable - private static String parseClassSignature(CharacterIterator signatureIterator, List convertedInterfaces) throws ClsFormatException { - String convertedSuper = SignatureParsing.parseTopLevelClassRefSignature(signatureIterator); - while (signatureIterator.current() != CharacterIterator.DONE) { - String ifs = SignatureParsing.parseTopLevelClassRefSignature(signatureIterator); - if (ifs == null) throw new ClsFormatException(); - convertedInterfaces.add(ifs); - } - return convertedSuper; - } - private static int packCommonFlags(int access) { int flags = 0; @@ -252,7 +258,7 @@ public class StubBuildingVisitor extends ClassVisitor { @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - return new AnnotationTextCollector(desc, new Consumer() { + return new AnnotationTextCollector(desc, myMapping, new Consumer() { @Override public void consume(String text) { new PsiAnnotationStubImpl(myModList, text); @@ -265,9 +271,8 @@ public class StubBuildingVisitor extends ClassVisitor { if ((access & Opcodes.ACC_SYNTHETIC) != 0) return; if (innerName == null || outerName == null) return; - if ((getClassName(outerName) + '.' + innerName).equals(myResult.getQualifiedName()) && myParent instanceof PsiFileStub) { - // our result is inner class - throw new OutOfOrderInnerClassException(); + if (myParent instanceof PsiFileStub && myInternalName.equals(name)) { + throw new OutOfOrderInnerClassException(); // our result is inner class } if (myInternalName.equals(outerName)) { @@ -286,35 +291,24 @@ public class StubBuildingVisitor extends ClassVisitor { byte flags = PsiFieldStubImpl.packFlags((access & Opcodes.ACC_ENUM) != 0, (access & Opcodes.ACC_DEPRECATED) != 0, false, false); TypeInfo type = fieldType(desc, signature); - String initializer = constToString(value, type.text, false); + String initializer = constToString(value, type.text, false, myMapping); PsiFieldStub stub = new PsiFieldStubImpl(myResult, name, type, initializer, flags); PsiModifierListStub modList = new PsiModifierListStubImpl(stub, packFieldFlags(access)); - return new AnnotationCollectingVisitor(modList); + return new AnnotationCollectingVisitor(modList, myMapping); } - @NotNull - public static TypeInfo fieldType(String desc, String signature) { + private TypeInfo fieldType(String desc, String signature) { + String type = null; if (signature != null) { try { - return TypeInfo.fromString(SignatureParsing.parseTypeString(new StringCharacterIterator(signature, 0))); - } - catch (ClsFormatException e) { - return fieldTypeViaDescription(desc); + type = SignatureParsing.parseTypeString(new StringCharacterIterator(signature), myMapping); } + catch (ClsFormatException e) { LOG.warn(signature, e); } } - else { - return fieldTypeViaDescription(desc); + if (type == null) { + type = toJavaType(Type.getType(desc), myMapping); } - } - - @NotNull - private static TypeInfo fieldTypeViaDescription(@NotNull String desc) { - Type type = Type.getType(desc); - int dim = type.getSort() == Type.ARRAY ? type.getDimensions() : 0; - if (dim > 0) { - type = type.getElementType(); - } - return new TypeInfo(getTypeText(type), (byte)dim, false, PsiAnnotationStub.EMPTY_ARRAY); + return TypeInfo.fromString(type, false); } private static final String[] parameterNames = {"p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9"}; @@ -327,50 +321,65 @@ public class StubBuildingVisitor extends ClassVisitor { // However Scala compiler erroneously generates ACC_BRIDGE instead of ACC_SYNTHETIC flag for in-trait implementation delegation. // See IDEA-78649 if ((access & Opcodes.ACC_SYNTHETIC) != 0) return null; - + if (name == null) return null; if (SYNTHETIC_CLASS_INIT_METHOD.equals(name)) return null; // skip semi-synthetic enum methods boolean isEnum = myResult.isEnum(); if (isEnum) { if ("values".equals(name) && desc.startsWith("()")) return null; + //noinspection SpellCheckingInspection if ("valueOf".equals(name) && desc.startsWith("(Ljava/lang/String;)")) return null; } - boolean isDeprecated = (access & Opcodes.ACC_DEPRECATED) != 0; boolean isConstructor = SYNTHETIC_INIT_METHOD.equals(name); + boolean isDeprecated = (access & Opcodes.ACC_DEPRECATED) != 0; boolean isVarargs = (access & Opcodes.ACC_VARARGS) != 0; + boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; boolean isAnnotationMethod = myResult.isAnnotationType(); - if (!isConstructor && name == null) return null; - byte flags = PsiMethodStubImpl.packFlags(isConstructor, isAnnotationMethod, isVarargs, isDeprecated, false, false); String canonicalMethodName = isConstructor ? myResult.getName() : name; - List args = new ArrayList(); - List throwables = exceptions != null ? new ArrayList() : null; - int modifiersMask = packMethodFlags(access, myResult.isInterface()); - PsiMethodStubImpl stub = new PsiMethodStubImpl(myResult, canonicalMethodName, flags, signature, args, throwables, desc, modifiersMask); - - PsiModifierListStub modList = (PsiModifierListStub)stub.findChildStubByType(JavaStubElementTypes.MODIFIER_LIST); - assert modList != null : stub; - - if (isEnum && isConstructor && signature == null && args.size() >= 2 && JAVA_LANG_STRING.equals(args.get(0)) && "int".equals(args.get(1))) { - // exclude synthetic enum constructor parameters - args = args.subList(2, args.size()); + MethodInfo info = null; + boolean generic = false; + if (signature != null) { + try { + info = parseMethodSignature(signature, exceptions); + generic = true; + } + catch (ClsFormatException e) { LOG.warn(signature, e); } + } + if (info == null) { + info = parseMethodDescription(desc, exceptions); } - boolean isNonStaticInnerClassConstructor = - isConstructor && !(myParent instanceof PsiFileStub) && (myModList.getModifiersMask() & Opcodes.ACC_STATIC) == 0; - boolean parsedViaGenericSignature = stub.isParsedViaGenericSignature(); - boolean shouldSkipFirstParamForNonStaticInnerClassConstructor = !parsedViaGenericSignature && isNonStaticInnerClassConstructor; + PsiMethodStubImpl stub = new PsiMethodStubImpl(myResult, canonicalMethodName, TypeInfo.fromString(info.returnType, false), flags, null); + + PsiModifierListStub modList = new PsiModifierListStubImpl(stub, packMethodFlags(access, myResult.isInterface())); + + PsiTypeParameterListStub list = new PsiTypeParameterListStubImpl(stub); + for (Pair parameter : info.typeParameters) { + PsiTypeParameterStub parameterStub = new PsiTypeParameterStubImpl(list, StringRef.fromString(parameter.first)); + newReferenceList(JavaStubElementTypes.EXTENDS_BOUND_LIST, parameterStub, parameter.second); + } + + boolean isEnumConstructor = isEnum && isConstructor; + boolean isInnerClassConstructor = isConstructor && !(myParent instanceof PsiFileStub) && (myModList.getModifiersMask() & Opcodes.ACC_STATIC) == 0; + + List args = info.argTypes; + if (!generic && isEnumConstructor && args.size() >= 2 && JAVA_LANG_STRING.equals(args.get(0)) && "int".equals(args.get(1))) { + // omit synthetic enum constructor parameters + args = args.subList(2, args.size()); + } PsiParameterListStubImpl parameterList = new PsiParameterListStubImpl(stub); int paramCount = args.size(); PsiParameterStubImpl[] paramStubs = new PsiParameterStubImpl[paramCount]; for (int i = 0; i < paramCount; i++) { - if (shouldSkipFirstParamForNonStaticInnerClassConstructor && i == 0) continue; + // omit synthetic inner class constructor parameter + if (i == 0 && !generic && isInnerClassConstructor) continue; String arg = args.get(i); boolean isEllipsisParam = isVarargs && i == paramCount - 1; @@ -382,115 +391,121 @@ public class StubBuildingVisitor extends ClassVisitor { new PsiModifierListStubImpl(parameterStub, 0); } - String[] thrownTypes = buildThrowsList(exceptions, throwables, parsedViaGenericSignature); - newReferenceList(JavaStubElementTypes.THROWS_LIST, stub, thrownTypes); + newReferenceList(JavaStubElementTypes.THROWS_LIST, stub, ArrayUtil.toStringArray(info.throwTypes)); - int localVarIgnoreCount = (access & Opcodes.ACC_STATIC) != 0 ? 0 : isConstructor && isEnum ? 3 : 1; - int paramIgnoreCount = isConstructor && isEnum ? 2 : isNonStaticInnerClassConstructor ? 1 : 0; - return new AnnotationParamCollectingVisitor(stub, modList, localVarIgnoreCount, paramIgnoreCount, paramCount, paramStubs); + int localVarIgnoreCount = isStatic ? 0 : isEnumConstructor ? 3 : 1; + int paramIgnoreCount = isEnumConstructor ? 2 : isInnerClassConstructor ? 1 : 0; + return new AnnotationParamCollectingVisitor(stub, modList, localVarIgnoreCount, paramIgnoreCount, paramCount, paramStubs, myMapping); } - private static String[] buildThrowsList(String[] exceptions, List throwables, boolean parsedViaGenericSignature) { - if (exceptions == null) return ArrayUtil.EMPTY_STRING_ARRAY; + private MethodInfo parseMethodSignature(String signature, String[] exceptions) throws ClsFormatException { + MethodInfo result = new MethodInfo(); + CharacterIterator iterator = new StringCharacterIterator(signature); - if (parsedViaGenericSignature && throwables != null && exceptions.length > throwables.size()) { - // There seem to be an inconsistency (or bug) in class format. For instance, java.lang.Class.forName() method has - // signature equal to "(Ljava/lang/String;)Ljava/lang/Class<*>;" (i.e. no exceptions thrown) but exceptions actually not empty, - // method throws ClassNotFoundException - parsedViaGenericSignature = false; - } + result.typeParameters = SignatureParsing.parseTypeParametersDeclaration(iterator, myMapping); - if (parsedViaGenericSignature && throwables != null) { - return ArrayUtil.toStringArray(throwables); + if (iterator.current() != '(') throw new ClsFormatException(); + iterator.next(); + if (iterator.current() == ')') { + result.argTypes = ContainerUtil.emptyList(); } else { - String[] converted = ArrayUtil.newStringArray(exceptions.length); - for (int i = 0; i < converted.length; i++) { - converted[i] = getClassName(exceptions[i]); + result.argTypes = ContainerUtil.newSmartList(); + while (iterator.current() != ')' && iterator.current() != CharacterIterator.DONE) { + result.argTypes.add(SignatureParsing.parseTypeString(iterator, myMapping)); } - return converted; - } - } - - @NotNull - public static String parseMethodViaDescription(@NotNull String desc, @NotNull PsiMethodStubImpl stub, @NotNull List args) { - String returnType = getTypeText(Type.getReturnType(desc)); - Type[] argTypes = Type.getArgumentTypes(desc); - for (Type argType : argTypes) { - args.add(getTypeText(argType)); - } - new PsiTypeParameterListStubImpl(stub); - return returnType; - } - - @NotNull - public static String parseMethodViaGenericSignature(@NotNull String signature, - @NotNull PsiMethodStubImpl stub, - @NotNull List args, - @Nullable List throwables) throws ClsFormatException { - StringCharacterIterator iterator = new StringCharacterIterator(signature); - SignatureParsing.parseTypeParametersDeclaration(iterator, stub); - - if (iterator.current() != '(') { - throw new ClsFormatException(); + if (iterator.current() != ')') throw new ClsFormatException(); } iterator.next(); - while (iterator.current() != ')' && iterator.current() != CharacterIterator.DONE) { - args.add(SignatureParsing.parseTypeString(iterator)); - } - - if (iterator.current() != ')') { - throw new ClsFormatException(); - } - iterator.next(); - - String returnType = SignatureParsing.parseTypeString(iterator); + result.returnType = SignatureParsing.parseTypeString(iterator, myMapping); + result.throwTypes = null; while (iterator.current() == '^') { iterator.next(); - String exType = SignatureParsing.parseTypeString(iterator); - if (throwables != null) { - throwables.add(exType); - } + if (result.throwTypes == null) result.throwTypes = ContainerUtil.newSmartList(); + result.throwTypes.add(SignatureParsing.parseTypeString(iterator, myMapping)); + } + if (exceptions != null && (result.throwTypes == null || exceptions.length > result.throwTypes.size())) { + // a signature may be inconsistent with exception list - in this case, the more complete list takes precedence + result.throwTypes = ContainerUtil.map(exceptions, new Function() { + @Override + public String fun(String name) { + return myMapping.fun(name); + } + }); } - return returnType; + return result; } + private MethodInfo parseMethodDescription(String desc, String[] exceptions) { + MethodInfo result = new MethodInfo(); + result.typeParameters = ContainerUtil.emptyList(); + result.returnType = toJavaType(Type.getReturnType(desc), myMapping); + result.argTypes = ContainerUtil.map(Type.getArgumentTypes(desc), new Function() { + @Override + public String fun(Type type) { + return toJavaType(type, myMapping); + } + }); + result.throwTypes = exceptions == null ? null : ContainerUtil.map(exceptions, new Function() { + @Override + public String fun(String name) { + return myMapping.fun(name); + } + }); + return result; + } + + + private static class ClassInfo { + private List> typeParameters; + private String superName; + private List interfaceNames; + } + + private static class MethodInfo { + private List> typeParameters; + private String returnType; + private List argTypes; + private List throwTypes; + } private static class AnnotationTextCollector extends AnnotationVisitor { private final StringBuilder myBuilder = new StringBuilder(); + private final Function myMapping; private final Consumer myCallback; + private boolean hasPrefix = false; private boolean hasParams = false; - private final String myDesc; - public AnnotationTextCollector(@Nullable String desc, Consumer callback) { + public AnnotationTextCollector(@Nullable String desc, Function mapping, Consumer callback) { super(ASM_API); + myMapping = mapping; myCallback = callback; - myDesc = desc; if (desc != null) { - myBuilder.append('@').append(getTypeText(Type.getType(desc))); + hasPrefix = true; + myBuilder.append('@').append(toJavaType(Type.getType(desc), myMapping)); } } @Override public void visit(String name, Object value) { valuePairPrefix(name); - myBuilder.append(constToString(value, null, true)); + myBuilder.append(constToString(value, null, true, myMapping)); } @Override public void visitEnum(String name, String desc, String value) { valuePairPrefix(name); - myBuilder.append(getTypeText(Type.getType(desc))).append('.').append(value); + myBuilder.append(toJavaType(Type.getType(desc), myMapping)).append('.').append(value); } private void valuePairPrefix(String name) { if (!hasParams) { hasParams = true; - if (myDesc != null) { + if (hasPrefix) { myBuilder.append('('); } } @@ -506,7 +521,7 @@ public class StubBuildingVisitor extends ClassVisitor { @Override public AnnotationVisitor visitAnnotation(String name, String desc) { valuePairPrefix(name); - return new AnnotationTextCollector(desc, new Consumer() { + return new AnnotationTextCollector(desc, myMapping, new Consumer() { @Override public void consume(String text) { myBuilder.append(text); @@ -518,7 +533,7 @@ public class StubBuildingVisitor extends ClassVisitor { public AnnotationVisitor visitArray(String name) { valuePairPrefix(name); myBuilder.append('{'); - return new AnnotationTextCollector(null, new Consumer() { + return new AnnotationTextCollector(null, myMapping, new Consumer() { @Override public void consume(String text) { myBuilder.append(text).append('}'); @@ -528,7 +543,7 @@ public class StubBuildingVisitor extends ClassVisitor { @Override public void visitEnd() { - if (hasParams && myDesc != null) { + if (hasPrefix && hasParams) { myBuilder.append(')'); } myCallback.consume(myBuilder.toString()); @@ -537,15 +552,17 @@ public class StubBuildingVisitor extends ClassVisitor { private static class AnnotationCollectingVisitor extends FieldVisitor { private final PsiModifierListStub myModList; + private final Function myMapping; - private AnnotationCollectingVisitor(PsiModifierListStub modList) { + private AnnotationCollectingVisitor(PsiModifierListStub modList, Function mapping) { super(ASM_API); myModList = modList; + myMapping = mapping; } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - return new AnnotationTextCollector(desc, new Consumer() { + return new AnnotationTextCollector(desc, myMapping, new Consumer() { @Override public void consume(String text) { new PsiAnnotationStubImpl(myModList, text); @@ -561,15 +578,17 @@ public class StubBuildingVisitor extends ClassVisitor { private final int myParamIgnoreCount; private final int myParamCount; private final PsiParameterStubImpl[] myParamStubs; + private final Function myMapping; private int myUsedParamSize = 0; private int myUsedParamCount = 0; - private AnnotationParamCollectingVisitor(@NotNull PsiMethodStub owner, - @NotNull PsiModifierListStub modList, + private AnnotationParamCollectingVisitor(PsiMethodStub owner, + PsiModifierListStub modList, int ignoreCount, int paramIgnoreCount, int paramCount, - @NotNull PsiParameterStubImpl[] paramStubs) { + PsiParameterStubImpl[] paramStubs, + Function mapping) { super(ASM_API); myOwner = owner; myModList = modList; @@ -577,11 +596,12 @@ public class StubBuildingVisitor extends ClassVisitor { myParamIgnoreCount = paramIgnoreCount; myParamCount = paramCount; myParamStubs = paramStubs; + myMapping = mapping; } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - return new AnnotationTextCollector(desc, new Consumer() { + return new AnnotationTextCollector(desc, myMapping, new Consumer() { @Override public void consume(String text) { new PsiAnnotationStubImpl(myModList, text); @@ -591,7 +611,7 @@ public class StubBuildingVisitor extends ClassVisitor { @Override public AnnotationVisitor visitAnnotationDefault() { - return new AnnotationTextCollector(null, new Consumer() { + return new AnnotationTextCollector(null, myMapping, new Consumer() { @Override public void consume(String text) { ((PsiMethodStubImpl)myOwner).setDefaultValueText(text); @@ -614,22 +634,14 @@ public class StubBuildingVisitor extends ClassVisitor { } myUsedParamCount = paramIndex + 1; - if ("D".equals(desc) || "J".equals(desc)) { - myUsedParamSize += 2; - } - else { - myUsedParamSize++; - } + myUsedParamSize += "D".equals(desc) || "J".equals(desc) ? 2 : 1; } } @Override @Nullable public AnnotationVisitor visitParameterAnnotation(final int parameter, String desc, boolean visible) { - if (parameter < myParamIgnoreCount) { - return null; - } - return new AnnotationTextCollector(desc, new Consumer() { + return parameter < myParamIgnoreCount ? null : new AnnotationTextCollector(desc, myMapping, new Consumer() { @Override public void consume(String text) { new PsiAnnotationStubImpl(myOwner.findParameter(parameter - myParamIgnoreCount).getModList(), text); @@ -639,7 +651,7 @@ public class StubBuildingVisitor extends ClassVisitor { } @Nullable - private static String constToString(@Nullable Object value, @Nullable String type, boolean anno) { + private static String constToString(@Nullable Object value, @Nullable String type, boolean anno, Function mapping) { if (value == null) return null; if (value instanceof String) { @@ -700,31 +712,98 @@ public class StubBuildingVisitor extends ClassVisitor { buffer.append('{'); for (int i = 0, length = Array.getLength(value); i < length; i++) { if (i > 0) buffer.append(", "); - buffer.append(constToString(Array.get(value, i), type, anno)); + buffer.append(constToString(Array.get(value, i), type, anno, mapping)); } buffer.append('}'); return buffer.toString(); } if (anno && value instanceof Type) { - return getTypeText((Type)value) + ".class"; + return toJavaType(((Type)value), mapping) + ".class"; } return null; } - private static String getClassName(String name) { - return getTypeText(Type.getObjectType(name)); + private static String toJavaType(Type type, Function mapping) { + int dimensions = 0; + if (type.getSort() == Type.ARRAY) { + dimensions = type.getDimensions(); + type = type.getElementType(); + } + String text = type.getSort() == Type.OBJECT ? mapping.fun(type.getInternalName()) : type.getClassName(); + if (dimensions > 0) text += StringUtil.repeat("[]", dimensions); + return text; } - @NotNull - private static String getTypeText(@NotNull Type type) { - String raw = type.getClassName(); - // As the '$' char is a valid java identifier and is actively used by byte code generators, the problem is - // which occurrences of this char should be replaced and which should not. - // Heuristic: replace only those $ occurrences that are surrounded non-"$" chars - // (most likely generated by javac to separate inner or anonymous class name) - // Leading and trailing $ chars should be left unchanged. - return raw.indexOf('$') >= 0 ? REGEX_PATTERN.matcher(raw).replaceAll("\\.") : raw; + private static Map> loadMapping(Object classSource) { + if (MAP_INNER_CLASSES_BY_TABLE && classSource instanceof VirtualFile) { + try { + final Map> mapping = ContainerUtil.newHashMap(); + + byte[] bytes = ((VirtualFile)classSource).contentsToByteArray(false); + new ClassReader(bytes).accept(new ClassVisitor(ASM_API) { + @Override + public void visitInnerClass(String name, String outerName, String innerName, int access) { + if (outerName != null && innerName != null) { + mapping.put(name, pair(outerName, innerName)); + } + } + }, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); + + if (!mapping.isEmpty()) { + return mapping; + } + } + catch (Exception ignored) { } + } + + return null; } + + private static Function createMapping(final Map> mapping) { + return new Function() { + @Override + public String fun(String internalName) { + String className = internalName; + + if (className.indexOf('$') >= 0) { + Pair p = mapping.get(className); + if (p != null) { + className = p.first; + if (p.second != null) { + className = fun(p.first) + '.' + p.second; + mapping.put(className, pair(className, (String)null)); + } + } + } + + return className.replace('/', '.'); + } + }; + } + + public static final Function GUESSING_MAPPER = new Function() { + @Override + public String fun(String internalName) { + String canonicalText = internalName; + + if (canonicalText.indexOf('$') >= 0) { + StringBuilder sb = new StringBuilder(canonicalText); + boolean updated = false; + for (int p = 0; p < sb.length(); p++) { + char c = sb.charAt(p); + if (c == '$' && p > 0 && sb.charAt(p - 1) != '/' && p < sb.length() - 1 && sb.charAt(p + 1) != '$') { + sb.setCharAt(p, '.'); + updated = true; + } + } + if (updated) { + canonicalText = sb.toString(); + } + } + + return canonicalText.replace('/', '.'); + } + }; } \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java index 2b9f44090593..5aa36a6b9580 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java @@ -17,7 +17,6 @@ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.PsiMethod; import com.intellij.psi.impl.cache.TypeInfo; -import com.intellij.psi.impl.compiled.StubBuildingVisitor; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; import com.intellij.psi.impl.java.stubs.PsiMethodStub; import com.intellij.psi.impl.java.stubs.PsiParameterListStub; @@ -25,7 +24,6 @@ import com.intellij.psi.impl.java.stubs.PsiParameterStub; import com.intellij.psi.stubs.StubBase; import com.intellij.psi.stubs.StubElement; import com.intellij.util.BitUtil; -import com.intellij.util.cls.ClsFormatException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -45,39 +43,7 @@ public class PsiMethodStubImpl extends StubBase implements PsiMethodS private static final int ANNOTATION = 0x04; private static final int DEPRECATED = 0x08; private static final int DEPRECATED_ANNOTATION = 0x10; - private static final int PARSED_VIA_GENERIC_SIGNATURE = 0x20; - private static final int HAS_DOC_COMMENT = 0x40; - - public PsiMethodStubImpl(StubElement parent, - String name, - byte flags, - String signature, - @NotNull List args, - @Nullable List throwables, - String desc, - int modifiersMask) { - super(parent, isAnnotationMethod(flags) ? JavaStubElementTypes.ANNOTATION_METHOD : JavaStubElementTypes.METHOD); - myName = name; - myDefaultValueText = null; - - new PsiModifierListStubImpl(this, modifiersMask); - - String returnType = null; - boolean parsedViaGenericSignature = false; - if (signature != null) { - try { - returnType = StubBuildingVisitor.parseMethodViaGenericSignature(signature, this, args, throwables); - parsedViaGenericSignature = true; - } - catch (ClsFormatException ignored) { } - } - if (returnType == null) { - returnType = StubBuildingVisitor.parseMethodViaDescription(desc, this, args); - } - - myReturnType = TypeInfo.fromString(returnType); - myFlags = (byte)(flags | (parsedViaGenericSignature ? PARSED_VIA_GENERIC_SIGNATURE : 0)); - } + private static final int HAS_DOC_COMMENT = 0x20; public PsiMethodStubImpl(StubElement parent, String name, @NotNull TypeInfo returnType, byte flags, @Nullable String defaultValueText) { super(parent, isAnnotationMethod(flags) ? JavaStubElementTypes.ANNOTATION_METHOD : JavaStubElementTypes.METHOD); @@ -97,10 +63,6 @@ public class PsiMethodStubImpl extends StubBase implements PsiMethodS return BitUtil.isSet(myFlags, VARARGS); } - public boolean isParsedViaGenericSignature() { - return BitUtil.isSet(myFlags, PARSED_VIA_GENERIC_SIGNATURE); - } - @Override public boolean isAnnotationMethod() { return isAnnotationMethod(myFlags); diff --git a/java/java-tests/testSrc/com/intellij/psi/SignatureParsingTest.java b/java/java-tests/testSrc/com/intellij/psi/SignatureParsingTest.java index 93ecdd6436b0..71f59f04e2ed 100644 --- a/java/java-tests/testSrc/com/intellij/psi/SignatureParsingTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/SignatureParsingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -16,6 +16,7 @@ package com.intellij.psi; import com.intellij.psi.impl.compiled.SignatureParsing; +import com.intellij.psi.impl.compiled.StubBuildingVisitor; import com.intellij.util.cls.ClsFormatException; import org.junit.Test; @@ -29,8 +30,18 @@ import static org.junit.Assert.assertEquals; public class SignatureParsingTest { @Test public void testVarianceAmbiguity() throws ClsFormatException { - assertEquals("Psi", SignatureParsing.parseTypeString(new StringCharacterIterator("LPsi<*TP>;"))); - assertEquals("Psi", SignatureParsing.parseTypeString(new StringCharacterIterator("LPsi<+TP>;"))); - assertEquals("Psi", SignatureParsing.parseTypeString(new StringCharacterIterator("LPsi<-TP>;"))); + parseTypeString("Psi", "LPsi<*TP>;"); + parseTypeString("Psi", "LPsi<+TP>;"); + parseTypeString("Psi", "LPsi<-TP>;"); } -} + + @Test + public void testMapping() throws ClsFormatException { + parseTypeString("p.Obj.I", "Lp/Obj$I;"); + parseTypeString("p.Obj$.I", "Lp/Obj$$I;"); + } + + private static void parseTypeString(String expected, String signature) throws ClsFormatException { + assertEquals(expected, SignatureParsing.parseTypeString(new StringCharacterIterator(signature), StubBuildingVisitor.GUESSING_MAPPER)); + } +} \ No newline at end of file diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index dd451323226d..1d09e4d18c56 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -302,6 +302,11 @@ java.max.package.name.length.description=An upper length limit on string that th java.correct.class.type.by.place.resolve.scope=true java.correct.class.type.by.place.resolve.scope.description=When resolving Java references, use the resolve scope of the currently processed source file +java.lib.inner.class.detection.by.table=false +java.lib.inner.class.detection.by.table.description=When 'true', IDEA will use "InnerClasses" .class file attribute to resolve \ + binary names (like "Map$Entry") into a source form ("Map.Entry"). Some compilers though do not populate this table correctly. \ + Cache invalidation needed when changing this value. + documentation.component.editor.font=false ide.completion.show.better.matching.classes=true diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitFieldsFileIndex.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitFieldsFileIndex.java index e48a87c9c172..c269e7de8a01 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitFieldsFileIndex.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitFieldsFileIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -20,8 +20,9 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.impl.cache.TypeInfo; +import com.intellij.psi.impl.compiled.SignatureParsing; import com.intellij.psi.impl.compiled.StubBuildingVisitor; +import com.intellij.util.cls.ClsFormatException; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.*; import com.intellij.util.indexing.FileBasedIndex.InputFilter; @@ -32,10 +33,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.org.objectweb.asm.ClassReader; import org.jetbrains.org.objectweb.asm.ClassVisitor; import org.jetbrains.org.objectweb.asm.FieldVisitor; +import org.jetbrains.org.objectweb.asm.Type; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.text.StringCharacterIterator; import java.util.Collection; import java.util.Collections; import java.util.Map; @@ -123,8 +126,8 @@ public class GroovyTraitFieldsFileIndex private static Map> mapInner(@NotNull FileContent inputData) { final int key = FileBasedIndex.getFileId(inputData.getFile()); final Map> result = ContainerUtil.newHashMap(); - new ClassReader(inputData.getContent()).accept(new ClassVisitor(ASM5) { + new ClassReader(inputData.getContent()).accept(new ClassVisitor(ASM5) { @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { processField(access, name, desc, signature); @@ -133,6 +136,7 @@ public class GroovyTraitFieldsFileIndex private void processField(int access, String name, String desc, String signature) { if ((access & ACC_SYNTHETIC) == 0) return; + final boolean isStatic; final boolean isPublic; Pair p; @@ -151,7 +155,7 @@ public class GroovyTraitFieldsFileIndex return; } - final String typeString = TypeInfo.createTypeText(StubBuildingVisitor.fieldType(desc, signature)); + final String typeString = fieldType(desc, signature); if (typeString == null) return; final int delimiter = name.indexOf(DELIMITER); @@ -178,7 +182,20 @@ public class GroovyTraitFieldsFileIndex return Pair.create(null, input); } } - }, ClassReader.SKIP_FRAMES); + + private String fieldType(String desc, String signature) { + if (signature != null) { + try { + return SignatureParsing.parseTypeString(new StringCharacterIterator(signature), StubBuildingVisitor.GUESSING_MAPPER); + } + catch (ClsFormatException ignored) { } + } + + String raw = Type.getType(desc).getClassName(); + return StubBuildingVisitor.GUESSING_MAPPER.fun(raw); + } + }, ClassReader.SKIP_CODE); + return result; } From ad5d26fc8e1e198eac8551a5d913d329c83501ef Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Thu, 14 Jan 2016 14:16:14 +0300 Subject: [PATCH 08/25] Test fix --- .../intellij/designer/DesignerToolWindowManager.java | 11 ++++++++--- .../designer/palette/PaletteToolWindowManager.java | 10 ++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/plugins/ui-designer-core/src/com/intellij/designer/DesignerToolWindowManager.java b/plugins/ui-designer-core/src/com/intellij/designer/DesignerToolWindowManager.java index a35be4d28697..5ebc2a4c94ef 100644 --- a/plugins/ui-designer-core/src/com/intellij/designer/DesignerToolWindowManager.java +++ b/plugins/ui-designer-core/src/com/intellij/designer/DesignerToolWindowManager.java @@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable; * @author Alexander Lobas */ public final class DesignerToolWindowManager extends AbstractToolWindowManager { - private final DesignerToolWindow myToolWindowContent; + private DesignerToolWindow myToolWindowContent; ////////////////////////////////////////////////////////////////////////////////////////// // @@ -43,7 +43,6 @@ public final class DesignerToolWindowManager extends AbstractToolWindowManager { public DesignerToolWindowManager(Project project, FileEditorManager fileEditorManager) { super(project, fileEditorManager); - myToolWindowContent = new DesignerToolWindow(project, true); } public static DesignerToolWindow getInstance(DesignerEditorPanel designer) { @@ -67,6 +66,10 @@ public final class DesignerToolWindowManager extends AbstractToolWindowManager { @Override protected void initToolWindow() { + if (myToolWindowContent == null) { + myToolWindowContent = new DesignerToolWindow(myProject, true); + } + myToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(DesignerBundle.message("designer.toolwindow.name"), false, getAnchor(), myProject, true); myToolWindow.setIcon(UIDesignerNewIcons.ToolWindow); @@ -110,7 +113,9 @@ public final class DesignerToolWindowManager extends AbstractToolWindowManager { @Override public void disposeComponent() { - myToolWindowContent.dispose(); + if (myToolWindowContent != null) { + myToolWindowContent.dispose(); + } } @NotNull diff --git a/plugins/ui-designer-core/src/com/intellij/designer/palette/PaletteToolWindowManager.java b/plugins/ui-designer-core/src/com/intellij/designer/palette/PaletteToolWindowManager.java index 3fddf66eaad6..fa30fcbff759 100644 --- a/plugins/ui-designer-core/src/com/intellij/designer/palette/PaletteToolWindowManager.java +++ b/plugins/ui-designer-core/src/com/intellij/designer/palette/PaletteToolWindowManager.java @@ -34,7 +34,7 @@ import org.jetbrains.annotations.Nullable; * @author Alexander Lobas */ public class PaletteToolWindowManager extends AbstractToolWindowManager { - private final PalettePanel myToolWindowPanel = new PalettePanel(); + private PalettePanel myToolWindowPanel; ////////////////////////////////////////////////////////////////////////////////////////// // @@ -66,6 +66,10 @@ public class PaletteToolWindowManager extends AbstractToolWindowManager { @Override protected void initToolWindow() { + if (myToolWindowPanel == null) { + myToolWindowPanel = new PalettePanel(); + } + myToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow("Palette\t", false, getAnchor(), myProject, true); myToolWindow.setIcon(AllIcons.Toolwindows.ToolWindowPalette); initGearActions(); @@ -100,7 +104,9 @@ public class PaletteToolWindowManager extends AbstractToolWindowManager { @Override public void disposeComponent() { - myToolWindowPanel.dispose(); + if (myToolWindowPanel != null) { + myToolWindowPanel.dispose(); + } } @NotNull From 5b730b20f9243daae2b503c4ffc648cb26d30e56 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 14 Jan 2016 14:38:48 +0300 Subject: [PATCH 09/25] diff: compare file paths, not their presentations shouldn't affect anything, but presentableUrl can change one day --- .../diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java b/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java index 91c1c2b7958e..20f632eabf84 100644 --- a/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java @@ -129,7 +129,7 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory { @NotNull public static String getTitle(@NotNull FilePath path1, @NotNull FilePath path2, @NotNull String separator) { - if ((path1.isDirectory() || path2.isDirectory()) && path1.getPresentableUrl().equals(path2.getPresentableUrl())) { + if ((path1.isDirectory() || path2.isDirectory()) && path1.getPath().equals(path2.getPath())) { return path1.getPresentableUrl(); } From 20ba3cc3756c5eb8e2e0f56379a0740b05e2d686 Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Thu, 14 Jan 2016 14:47:13 +0300 Subject: [PATCH 10/25] artifacts with custom linux jdk for PyCharm (PY and PC). --- python/build/pycharm_community_build.gant | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/build/pycharm_community_build.gant b/python/build/pycharm_community_build.gant index d5d6f2a84f61..9baaff86e553 100644 --- a/python/build/pycharm_community_build.gant +++ b/python/build/pycharm_community_build.gant @@ -180,6 +180,9 @@ public layoutCommunity(String classesPath, Set usedJars) { if (p("jdk.linux") != "false") { buildTarGz(tarRoot, "$paths.artifacts/pycharmPC-${buildName}.tar", [paths.distAll, paths.distUnix, "${home}/out/pycharm/jdk.linux"], ["jre/jre/bin/*"]) } + if (p("jdk.custom.linux") != "false") { + buildTarGz(tarRoot, "$paths.artifacts/pycharmPC${buildName}-custom-jdk-linux.tar", [paths.distAll, paths.distUnix, "${home}/out/pycharm/jdk.custom.linux"], ["jre/jre/bin/*"]) + } String macAppRoot = isEap() ? "PyCharm CE ${p("component.version.major")}.${p("component.version.minor")} EAP.app/Contents" : "PyCharm CE.app/Contents" buildMacZip(macAppRoot, "${paths.artifacts}/pycharmPC-${buildNumber}.mac.zip", [paths.distAll], paths.distMac) From 48139e0d54bbeafa8890e3596806b0c46ccccd05 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 Jan 2016 14:57:48 +0300 Subject: [PATCH 11/25] logging for EA-77200 --- .../intellij/debugger/engine/PositionManagerImpl.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index 3c0ed6780f10..2b46e1ac1ff4 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -41,6 +41,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.DocumentUtil; import com.intellij.util.Function; +import com.intellij.util.PairProcessor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.EmptyIterable; import com.sun.jdi.AbsentInformationException; @@ -432,7 +433,15 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio } } else { - LOG.error("Local or anonymous class has no non-local parent"); + final StringBuilder sb = new StringBuilder(); + PsiTreeUtil.treeWalkUp(psiClass, null, new PairProcessor() { + @Override + public boolean process(PsiElement element, PsiElement element2) { + sb.append(element); + return true; + } + }); + LOG.error("Local or anonymous class " + psiClass + " has no non-local parent, parents:" + sb); } } else { From 1df6a01247b9d351d0cb16dc7084097e811bc99f Mon Sep 17 00:00:00 2001 From: irengrig Date: Thu, 14 Jan 2016 12:58:32 +0100 Subject: [PATCH 12/25] Revert: both capturing process classes to listen to the progress manager and be cancellable --- .../process/CapturingProcessHandler.java | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/platform/platform-api/src/com/intellij/execution/process/CapturingProcessHandler.java b/platform/platform-api/src/com/intellij/execution/process/CapturingProcessHandler.java index 13331d11520f..d37946444b95 100644 --- a/platform/platform-api/src/com/intellij/execution/process/CapturingProcessHandler.java +++ b/platform/platform-api/src/com/intellij/execution/process/CapturingProcessHandler.java @@ -18,9 +18,7 @@ package com.intellij.execution.process; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -67,34 +65,15 @@ public class CapturingProcessHandler extends OSProcessHandler { public ProcessOutput runProcess() { startNotify(); - if (waitForProcessListeningProgress(this)) { + if (waitFor()) { myOutput.setExitCode(getProcess().exitValue()); } else { LOG.info("runProcess: exit value unavailable"); } - return myOutput; } - public static boolean waitForProcessListeningProgress(ProcessHandler handler) { - final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - if (indicator != null) { - while (!handler.waitFor(300)) { - if (indicator.isCanceled()) { - handler.destroyProcess(); - throw new ProcessCanceledException(); - } - } - } else { - if (!handler.waitFor()) { - LOG.info("runProcess: exit value unavailable"); - return false; - } - } - return true; - } - /** * Starts process with specified timeout * From a7cb6d8fe52891aa2db902654289bbbdf944eb4f Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 Jan 2016 15:30:43 +0300 Subject: [PATCH 13/25] unable to start with empty config (IDEA-CR-7815) --- platform/platform-api/src/com/intellij/util/ui/Animator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/util/ui/Animator.java b/platform/platform-api/src/com/intellij/util/ui/Animator.java index f23281871aff..99ce196f9631 100644 --- a/platform/platform-api/src/com/intellij/util/ui/Animator.java +++ b/platform/platform-api/src/com/intellij/util/ui/Animator.java @@ -106,7 +106,9 @@ public abstract class Animator implements Disposable { } private void animationDone() { - ApplicationManager.getApplication().assertIsDispatchThread(); + // NOT ApplicationManager.getApplication().assertIsDispatchThread() as Application may not be available when e.g. importing settings + assert SwingUtilities.isEventDispatchThread(); + stopTicker(); paintCycleEnd(); } From acc79a84209b248b90daff225426119bcb99202c Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 14 Jan 2016 13:45:28 +0100 Subject: [PATCH 14/25] [groovy] correct detection of trait field helper file --- .../typedef/GrTypeDefinitionMembersCache.java | 13 +++++++------ .../lang/resolve/GroovyTraitFieldsFileIndex.java | 5 ++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java index c21a4adf0fde..9030f80ad513 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java @@ -41,6 +41,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrTraitField; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrTraitMethod; import org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil; +import org.jetbrains.plugins.groovy.lang.resolve.GroovyTraitFieldsFileIndex; import org.jetbrains.plugins.groovy.lang.resolve.GroovyTraitFieldsFileIndex.TraitFieldDescriptor; import org.jetbrains.plugins.groovy.lang.resolve.ast.AstTransformContributor; @@ -308,6 +309,7 @@ public class GrTypeDefinitionMembersCache { LOG.assertTrue(trait != null); List traitFields = new TraitProcessor(trait, resolveResult.getSubstitutor()) { + @Override protected void processTrait(@NotNull final PsiClass trait, @NotNull final PsiSubstitutor substitutor) { if (trait instanceof GrTypeDefinition) { for (GrField field : ((GrTypeDefinition)trait).getCodeFields()) { @@ -315,15 +317,14 @@ public class GrTypeDefinitionMembersCache { } } else if (trait instanceof ClsClassImpl) { - final PsiClass traitFieldHelper = JavaPsiFacade.getInstance(trait.getProject()).findClass( - trait.getQualifiedName() + "$Trait$FieldHelper", trait.getResolveScope() - ); - if (traitFieldHelper == null) return; + final VirtualFile traitFile = trait.getContainingFile().getVirtualFile(); + if (traitFile == null) return; + final VirtualFile helperFile = traitFile.getParent().findChild(trait.getName() + GroovyTraitFieldsFileIndex.HELPER_SUFFIX); + if (helperFile == null) return; - final VirtualFile virtualFile = traitFieldHelper.getContainingFile().getVirtualFile(); final List> descriptors = FileBasedIndex.getInstance().getValues( INDEX_ID, - FileBasedIndex.getFileId(virtualFile), + FileBasedIndex.getFileId(helperFile), trait.getResolveScope() ); for (Collection traitFieldDescriptors : descriptors) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitFieldsFileIndex.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitFieldsFileIndex.java index c269e7de8a01..568b1cf9dd71 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitFieldsFileIndex.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitFieldsFileIndex.java @@ -56,10 +56,13 @@ public class GroovyTraitFieldsFileIndex DataExternalizer> { public static final ID> INDEX_ID = ID.create("groovy.trait.fields"); + + public static final String HELPER_SUFFIX = "$Trait$FieldHelper.class"; + public static final InputFilter INPUT_FILTER = new DefaultFileTypeSpecificInputFilter(JavaClassFileType.INSTANCE) { @Override public boolean acceptInput(@NotNull VirtualFile file) { - return StringUtil.endsWith(file.getNameSequence(), "$Trait$FieldHelper.class"); + return StringUtil.endsWith(file.getNameSequence(), HELPER_SUFFIX); } }; From 8b13206ac23f73e86441aff34cbd16360965ddc0 Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Wed, 13 Jan 2016 14:34:45 +0300 Subject: [PATCH 15/25] optimize imports --- .../com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/python/edu/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java b/python/edu/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java index 0f45a543a43b..a8c0082f9d99 100644 --- a/python/edu/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java +++ b/python/edu/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java @@ -6,7 +6,6 @@ import com.intellij.facet.ui.ValidationResult; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.FileTemplateUtil; -import com.intellij.ide.util.DirectoryUtil; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; @@ -16,7 +15,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.platform.DirectoryProjectGenerator; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiManager; -import com.jetbrains.edu.EduNames; import com.jetbrains.edu.courseFormat.Course; import com.jetbrains.edu.coursecreator.actions.CCCreateLesson; import com.jetbrains.edu.coursecreator.actions.CCCreateTask; @@ -53,7 +51,6 @@ public class PyCCProjectGenerator extends PythonProjectGenerator implements Dire return CourseCreatorPythonIcons.CourseCreationProjectType; } - @Override public void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir, @Nullable Object settings, @NotNull Module module) { @@ -64,7 +61,6 @@ public class PyCCProjectGenerator extends PythonProjectGenerator implements Dire public static void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir, @NotNull final String name, @NotNull final String[] authors, @NotNull final String description) { - final CCProjectService service = CCProjectService.getInstance(project); final Course course = new Course(); course.setName(name); From 0f52c9c13cd01f256e6eb7cfc4cc24438b022fd1 Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Thu, 14 Jan 2016 16:38:21 +0300 Subject: [PATCH 16/25] corrected pycharm PC artifact name. --- python/build/pycharm_community_build.gant | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/build/pycharm_community_build.gant b/python/build/pycharm_community_build.gant index 9baaff86e553..9241b5cd2a4c 100644 --- a/python/build/pycharm_community_build.gant +++ b/python/build/pycharm_community_build.gant @@ -178,10 +178,10 @@ public layoutCommunity(String classesPath, Set usedJars) { String tarRoot = isEap() ? "pycharm-community-$buildNumber" : "pycharm-community-${p("component.version.major")}.${p("component.version.minor")}" buildTarGz(tarRoot, "$paths.artifacts/pycharmPC-${buildNumber}-no-jdk.tar", [paths.distAll, paths.distUnix]) if (p("jdk.linux") != "false") { - buildTarGz(tarRoot, "$paths.artifacts/pycharmPC-${buildName}.tar", [paths.distAll, paths.distUnix, "${home}/out/pycharm/jdk.linux"], ["jre/jre/bin/*"]) + buildTarGz(tarRoot, "$paths.artifacts/pycharmPC-${buildNumber}.tar", [paths.distAll, paths.distUnix, "${home}/out/pycharm/jdk.linux"], ["jre/jre/bin/*"]) } if (p("jdk.custom.linux") != "false") { - buildTarGz(tarRoot, "$paths.artifacts/pycharmPC${buildName}-custom-jdk-linux.tar", [paths.distAll, paths.distUnix, "${home}/out/pycharm/jdk.custom.linux"], ["jre/jre/bin/*"]) + buildTarGz(tarRoot, "$paths.artifacts/pycharmPC-${buildNumber}-custom-jdk-linux.tar", [paths.distAll, paths.distUnix, "${home}/out/pycharm/jdk.custom.linux"], ["jre/jre/bin/*"]) } String macAppRoot = isEap() ? "PyCharm CE ${p("component.version.major")}.${p("component.version.minor")} EAP.app/Contents" : "PyCharm CE.app/Contents" From ef6711a76073642a4ef5c84ade85837f2a337170 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 14 Jan 2016 15:06:05 +0100 Subject: [PATCH 17/25] [java] inner class detection: optimization --- .../com/intellij/psi/ClassFileViewProvider.java | 14 +++++--------- .../intellij/psi/impl/compiled/ClsFileImpl.java | 7 +++++-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java index abd8fbe389d6..449aa574a47d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java +++ b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java @@ -31,6 +31,8 @@ import com.intellij.psi.impl.file.PsiBinaryFileImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.org.objectweb.asm.*; +import static com.intellij.psi.impl.compiled.ClsFileImpl.EMPTY_ATTRIBUTES; + /** * @author max */ @@ -60,7 +62,8 @@ public class ClassFileViewProvider extends SingleRootFileViewProvider { public static boolean isInnerClass(@NotNull VirtualFile file) { String name = file.getNameWithoutExtension(); - return name.indexOf('$') >= 0 && detectInnerClass(file); + int p = name.lastIndexOf('$', name.length() - 2); + return p > 0 && detectInnerClass(file); } private static boolean detectInnerClass(VirtualFile file) { @@ -75,22 +78,15 @@ public class ClassFileViewProvider extends SingleRootFileViewProvider { @Override public void visitOuterClass(String owner, String name, String desc) { ref.set(Boolean.TRUE); - throw new ProcessCanceledException(); } @Override public void visitInnerClass(String name, String outer, String inner, int access) { if (className.equals(name)) { ref.set(Boolean.TRUE); - throw new ProcessCanceledException(); } } - - @Override - public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { - throw new ProcessCanceledException(); - } - }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + }, EMPTY_ATTRIBUTES, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); } catch (ProcessCanceledException ignored) { } catch (Exception e) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java index a563e8107b56..431d1611e5da 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java @@ -69,6 +69,7 @@ import com.intellij.util.cls.ClsFormatException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.org.objectweb.asm.Attribute; import org.jetbrains.org.objectweb.asm.ClassReader; import java.io.IOException; @@ -595,7 +596,7 @@ public class ClsFileImpl extends ClsRepositoryPsiElement try { StubBuildingVisitor visitor = new StubBuildingVisitor(file, STRATEGY, stub, 0, className); - reader.accept(visitor, ClassReader.SKIP_FRAMES); + reader.accept(visitor, EMPTY_ATTRIBUTES, ClassReader.SKIP_FRAMES); PsiClassStub result = visitor.getResult(); if (result == null) return null; } @@ -629,9 +630,11 @@ public class ClsFileImpl extends ClsRepositoryPsiElement public void accept(VirtualFile innerClass, StubBuildingVisitor visitor) { try { byte[] bytes = innerClass.contentsToByteArray(false); - new ClassReader(bytes).accept(visitor, ClassReader.SKIP_FRAMES); + new ClassReader(bytes).accept(visitor, EMPTY_ATTRIBUTES, ClassReader.SKIP_FRAMES); } catch (IOException ignored) { } } }; + + public static final Attribute[] EMPTY_ATTRIBUTES = new Attribute[0]; } \ No newline at end of file From 1e2e2f77d3e8e6638f6caaf2cce00d7af23e6922 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 14 Jan 2016 15:08:09 +0100 Subject: [PATCH 18/25] Cleanup (forgotten catch) --- .../src/com/intellij/psi/ClassFileViewProvider.java | 1 - 1 file changed, 1 deletion(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java index 449aa574a47d..72017210db58 100644 --- a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java +++ b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java @@ -88,7 +88,6 @@ public class ClassFileViewProvider extends SingleRootFileViewProvider { } }, EMPTY_ATTRIBUTES, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); } - catch (ProcessCanceledException ignored) { } catch (Exception e) { Logger.getInstance(ClassFileViewProvider.class).warn(file.getPath(), e); } From 05253be08ad59320942551733db14d2fe12c637f Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Thu, 14 Jan 2016 17:46:28 +0300 Subject: [PATCH 19/25] PY-18203 Redundant parentheses quick fix produces syntactically incorrect code for tuples If parentheses expression contains binary expression where left and right are parentheses expressions too, we check if left and right contain tuples --- .../inspections/quickfix/RedundantParenthesesQuickFix.java | 3 ++- python/testData/inspections/RedundantParenthesesInTuples.py | 1 + .../inspections/RedundantParenthesesInTuples_after.py | 1 + python/testSrc/com/jetbrains/python/PyQuickFixTest.java | 5 +++++ 4 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 python/testData/inspections/RedundantParenthesesInTuples.py create mode 100644 python/testData/inspections/RedundantParenthesesInTuples_after.py diff --git a/python/src/com/jetbrains/python/inspections/quickfix/RedundantParenthesesQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/RedundantParenthesesQuickFix.java index 7224cccbf4d9..3c4343420c54 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/RedundantParenthesesQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/RedundantParenthesesQuickFix.java @@ -72,7 +72,8 @@ public class RedundantParenthesesQuickFix implements LocalQuickFix { right instanceof PyParenthesizedExpression) { PyExpression leftContained = ((PyParenthesizedExpression)left).getContainedExpression(); PyExpression rightContained = ((PyParenthesizedExpression)right).getContainedExpression(); - if (leftContained != null && rightContained != null) { + if (leftContained != null && rightContained != null && + !(leftContained instanceof PyTupleExpression) && !(rightContained instanceof PyTupleExpression)) { left.replace(leftContained); right.replace(rightContained); return true; diff --git a/python/testData/inspections/RedundantParenthesesInTuples.py b/python/testData/inspections/RedundantParenthesesInTuples.py new file mode 100644 index 000000000000..668372db89b9 --- /dev/null +++ b/python/testData/inspections/RedundantParenthesesInTuples.py @@ -0,0 +1 @@ +print("%d%s%s" % (((1,) + ("", "")))) \ No newline at end of file diff --git a/python/testData/inspections/RedundantParenthesesInTuples_after.py b/python/testData/inspections/RedundantParenthesesInTuples_after.py new file mode 100644 index 000000000000..31ac4040ce02 --- /dev/null +++ b/python/testData/inspections/RedundantParenthesesInTuples_after.py @@ -0,0 +1 @@ +print("%d%s%s" % ((1,) + ("", ""))) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index dded82dd8930..96deaf719141 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -244,6 +244,11 @@ public class PyQuickFixTest extends PyTestCase { doInspectionTest(PyRedundantParenthesesInspection.class, PyBundle.message("QFIX.redundant.parentheses"), true, true); } + // PY-18203 + public void testRedundantParenthesesInTuples() { + doInspectionTest(PyRedundantParenthesesInspection.class, PyBundle.message("QFIX.redundant.parentheses"), true, true); + } + // PY-1020 public void testChainedComparisons() { doInspectionTest(PyChainedComparisonsInspection.class, PyBundle.message("QFIX.chained.comparison"), true, true); From a06214e2525d005b633e012a676917acb1aa6cd5 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Thu, 14 Jan 2016 17:53:20 +0300 Subject: [PATCH 20/25] add incompatible plugin --- platform/platform-resources/src/brokenPlugins.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt index f00526448309..7575455aba21 100644 --- a/platform/platform-resources/src/brokenPlugins.txt +++ b/platform/platform-resources/src/brokenPlugins.txt @@ -1,7 +1,7 @@ // This file contains list of broken plugins. // Each line contains plugin ID and list of versions that are broken. // If plugin name or version contains a space you can quote it like in command line. -NodeJS 144.2562 144.2131 144.988 143.1138 143.1088 143.769 143.751 143.516 143.381.8 143.380.6 143.381.11 143.380.8 143.444 143.379.15 143.21 143.110 143.250 142.4426 142.4100 142.3858 142.3224 142.2650 142.2492 142.2481 142.2064 141.1108 140.2045 140.1669 140.642 139.173 139.105 139.496 139.1 139.8 138.2196 138.2254 138.1684 138.1744 138.1879 138.2051 138.1367 138.1495 138.1189 138.1145 138.937 138.1013 138.921 138.447 138.172 138.317 138.21 138.35 138.96 138.85 136.1205 134.1276 134.1163 134.1145 134.1081 134.1039 134.985 134.680 134.31 134.307 134.262 134.198 134.125 136.1141 +NodeJS 144.2986 144.2562 144.2131 144.988 143.1138 143.1088 143.769 143.751 143.516 143.381.8 143.380.6 143.381.11 143.380.8 143.444 143.379.15 143.21 143.110 143.250 142.4426 142.4100 142.3858 142.3224 142.2650 142.2492 142.2481 142.2064 141.1108 140.2045 140.1669 140.642 139.173 139.105 139.496 139.1 139.8 138.2196 138.2254 138.1684 138.1744 138.1879 138.2051 138.1367 138.1495 138.1189 138.1145 138.937 138.1013 138.921 138.447 138.172 138.317 138.21 138.35 138.96 138.85 136.1205 134.1276 134.1163 134.1145 134.1081 134.1039 134.985 134.680 134.31 134.307 134.262 134.198 134.125 136.1141 com.jetbrains.php 143.382.38 143.279 143.381.48 143.129 142.5282 142.2716 142.3969 142.4491 140.2765 141.332 139.732 139.659 139.496 139.173 139.105 138.2502 138.2000.2262 138.1751 138.1806 138.1505 138.1161 138.826 136.1768 136.1672 134.1456 133.982 133.679 133.51 133.326 131.98 131.374 131.332 131.235 131.205 130.1639 130.1481 130.1176 129.91 129.814 129.672 129.362 127.67 127.100 126.334 123.66 122.875 121.62 121.390 121.215 121.12 com.jetbrains.lang.ejs 131.17 131.12 com.jetbrains.twig 133.51 130.1639 From f7312cf0d809b606d43e8b8c61e50b750a0322dd Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 14 Jan 2016 15:58:33 +0100 Subject: [PATCH 21/25] [platform] update info XML validation (EA-77712) --- .../openapi/updateSettings/impl/UpdateInfo.kt | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfo.kt b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfo.kt index 76012065b95b..f782fc00376b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfo.kt +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -20,12 +20,13 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.BuildNumber import com.intellij.openapi.util.SystemInfo import org.jdom.Element +import org.jdom.JDOMException import java.text.ParseException import java.text.SimpleDateFormat import java.util.* class UpdatesInfo(node: Element) { - private val products = node.children.map { Product(it) } + private val products = node.getChildren("product").map { Product(it) } val productsCount: Int get() = products.size @@ -34,9 +35,9 @@ class UpdatesInfo(node: Element) { } class Product(node: Element) { - val name: String = node.getAttributeValue("name")!! + val name: String = node.getAttributeValue("name") ?: throw JDOMException("product.name missing") val channels: List = node.getChildren("channel").map { UpdateChannel(it) } - private val codes = node.getChildren("code").map { it.value }.toSet() + private val codes = node.getChildren("code").map { it.value.trim() }.toSet() fun hasCode(code: String): Boolean = codes.contains(code) @@ -51,8 +52,8 @@ class UpdateChannel(node: Element) { const val LICENSING_PRODUCTION = "production" } - val id: String = node.getAttributeValue("id")!! - val name: String = node.getAttributeValue("name")!! + val id: String = node.getAttributeValue("id") ?: throw JDOMException("channel.id missing") + val name: String = node.getAttributeValue("name") ?: throw JDOMException("channel.name missing") val status: ChannelStatus = ChannelStatus.fromCode(node.getAttributeValue("status")) val licensing: String = node.getAttributeValue("licensing", LICENSING_PRODUCTION) val majorVersion: Int = node.getAttributeValue("majorVersion")?.toInt() ?: -1 @@ -69,7 +70,7 @@ class UpdateChannel(node: Element) { } class BuildInfo(node: Element) : Comparable { - val number: BuildNumber = BuildNumber.fromString(node.getAttributeValue("number")!!) + val number: BuildNumber = BuildNumber.fromString(node.getAttributeValue("number") ?: throw JDOMException("build.number missing")) val apiVersion: BuildNumber = node.getAttributeValue("apiVersion")?.let { BuildNumber.fromString(it, number.productCode) } ?: number val version: String = node.getAttributeValue("version") ?: "" val message: String = node.getChild("message")?.value ?: "" @@ -110,13 +111,13 @@ class BuildInfo(node: Element) : Comparable { } class ButtonInfo(node: Element) { - val name: String = node.getAttributeValue("name")!! - val url: String = node.getAttributeValue("url")!! + val name: String = node.getAttributeValue("name") ?: throw JDOMException("button.name missing") + val url: String = node.getAttributeValue("url") ?: throw JDOMException("button.url missing") val isDownload: Boolean = node.getAttributeValue("download") != null // a button marked with this attribute is hidden when a patch is available } class PatchInfo(node: Element) { - val fromBuild: BuildNumber = BuildNumber.fromString(node.getAttributeValue("from")!!) + val fromBuild: BuildNumber = BuildNumber.fromString(node.getAttributeValue("from") ?: throw JDOMException("patch.from missing")) val size: String? = node.getAttributeValue("size") val isAvailable: Boolean = node.getAttributeValue("exclusions")?.split(",")?.none { it.trim() == osSuffix } ?: true From 361154efec429358e11e2efb67693ee9bdd8b2e2 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 14 Jan 2016 16:06:35 +0100 Subject: [PATCH 22/25] [util] minor optimization --- .../src/com/intellij/openapi/util/io/FileUtilRt.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java b/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java index 5dc28282a90c..38ba86d3c58d 100644 --- a/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java +++ b/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -18,6 +18,7 @@ package com.intellij.openapi.util.io; import com.intellij.openapi.diagnostic.LoggerRt; import com.intellij.openapi.util.SystemInfoRt; import com.intellij.openapi.util.text.StringUtilRt; +import com.intellij.util.ArrayUtilRt; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -616,6 +617,9 @@ public class FileUtilRt { @NotNull public static byte[] loadBytes(@NotNull InputStream stream, int length) throws IOException { + if (length == 0) { + return ArrayUtilRt.EMPTY_BYTE_ARRAY; + } byte[] bytes = new byte[length]; int count = 0; while (count < length) { From ea7c3845b87174d88310732a05686d168ee431d2 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 13 Jan 2016 17:35:27 +0300 Subject: [PATCH 23/25] cleanup --- .../intellij/util/concurrency/BoundedTaskExecutorTest.java | 4 ++-- .../com/intellij/util/concurrency/BoundedTaskExecutor.java | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/platform/platform-tests/testSrc/com/intellij/util/concurrency/BoundedTaskExecutorTest.java b/platform/platform-tests/testSrc/com/intellij/util/concurrency/BoundedTaskExecutorTest.java index 3ddfde6f5e11..1f39d04bd016 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/concurrency/BoundedTaskExecutorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/concurrency/BoundedTaskExecutorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -173,7 +173,7 @@ public class BoundedTaskExecutorTest extends TestCase { Future[] futures = new Future[N]; for (int i = 0; i < N; i++) { final int finalI = i; - futures[i] = executor.submit(() -> log.append(finalI).append(" ")); + futures[i] = executor.submit(() -> log.append(finalI+" ")); } for (int i = 0; i < N; i++) { expected.append(i).append(" "); diff --git a/platform/util/src/com/intellij/util/concurrency/BoundedTaskExecutor.java b/platform/util/src/com/intellij/util/concurrency/BoundedTaskExecutor.java index 2ea538cb54fd..339a2f94e990 100644 --- a/platform/util/src/com/intellij/util/concurrency/BoundedTaskExecutor.java +++ b/platform/util/src/com/intellij/util/concurrency/BoundedTaskExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -19,6 +19,7 @@ import com.intellij.diagnostic.ThreadDumper; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Disposer; import com.intellij.util.Function; +import com.intellij.util.ObjectUtils; import com.intellij.util.ReflectionUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -71,10 +72,10 @@ public class BoundedTaskExecutor extends AbstractExecutorService { // for diagnostics static Object info(Object task) { if (task instanceof FutureTask) { - task = ReflectionUtil.getField(task.getClass(), task, Callable.class, "callable"); + task = ObjectUtils.chooseNotNull(ReflectionUtil.getField(task.getClass(), task, Callable.class, "callable"), task.getClass()); } if (task instanceof Callable && task.getClass().getName().equals("java.util.concurrent.Executors$RunnableAdapter")) { - task = ReflectionUtil.getField(task.getClass(), task, Runnable.class, "task"); + task = ObjectUtils.chooseNotNull(ReflectionUtil.getField(task.getClass(), task, Runnable.class, "task"), task.getClass()); } return task; } From 9843d2e25039f9b79c78cee5c23eee41c9bc29a9 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 13 Jan 2016 19:25:40 +0300 Subject: [PATCH 24/25] cleanup --- .../openapi/wm/impl/status/InfoAndProgressPanel.java | 4 ++-- .../wm/impl/status/InlineProgressIndicator.java | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java index 5f76c973effe..5bca3646dec0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InfoAndProgressPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -672,7 +672,7 @@ public class InfoAndProgressPanel extends JPanel implements CustomStatusBarWidge } @Override - protected void queueRunningUpdate(final Runnable update) { + protected void queueRunningUpdate(@NotNull final Runnable update) { myUpdateQueue.queue(new Update(new Object(), false, 0) { @Override public void run() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InlineProgressIndicator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InlineProgressIndicator.java index 5e7131a25f13..cae90155dee7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InlineProgressIndicator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/InlineProgressIndicator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -65,6 +65,7 @@ public class InlineProgressIndicator extends ProgressIndicatorBase implements Di AllIcons.Process.Stop, AllIcons.Process.StopHovered) { }, new ActionListener() { + @Override public void actionPerformed(final ActionEvent e) { cancelRequest(); } @@ -163,7 +164,7 @@ public class InlineProgressIndicator extends ProgressIndicatorBase implements Di myText.setText(getText() != null ? getText() : ""); myText2.setText(getText2() != null ? getText2() : ""); - if (myCompact && myText.getText().length() == 0) { + if (myCompact && myText.getText().isEmpty()) { myText.setText(myInfo.getTitle()); } @@ -197,10 +198,11 @@ public class InlineProgressIndicator extends ProgressIndicatorBase implements Di updateAndRepaint(); } - protected void queueRunningUpdate(Runnable update) { + protected void queueRunningUpdate(@NotNull Runnable update) { update.run(); } + @Override protected void onProgressChange() { updateProgress(); } @@ -225,6 +227,7 @@ public class InlineProgressIndicator extends ProgressIndicatorBase implements Di myCompact = compact; myProcessName = processName; addMouseListener(new MouseAdapter() { + @Override public void mousePressed(final MouseEvent e) { if (UIUtil.isCloseClick(e) && getBounds().contains(e.getX(), e.getY())) { cancelRequest(); @@ -233,6 +236,7 @@ public class InlineProgressIndicator extends ProgressIndicatorBase implements Di }); } + @Override protected void paintComponent(final Graphics g) { if (myCompact) { super.paintComponent(g); @@ -272,6 +276,7 @@ public class InlineProgressIndicator extends ProgressIndicatorBase implements Di } } + @Override public void dispose() { if (myDisposed) return; From cc330da0e4bdc5d9d574506d1927252924205702 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 14 Jan 2016 17:53:49 +0300 Subject: [PATCH 25/25] fragment in debugger text field blinks on/off red --- .../impl/DaemonRespondToChangesTest.java | 47 +++++++++++++++++-- .../daemon/impl/GeneralHighlightingPass.java | 12 ++--- .../daemon/impl/UpdateHighlightersUtil.java | 8 ++-- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java index 0c47086d1d89..df6f45ea8c92 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -16,6 +16,7 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeHighlighting.*; +import com.intellij.codeInsight.EditorInfo; import com.intellij.codeInsight.completion.CompletionContributor; import com.intellij.codeInsight.daemon.*; import com.intellij.codeInsight.daemon.impl.quickfix.DeleteCatchFix; @@ -112,6 +113,7 @@ import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; import com.intellij.psi.impl.DebugUtil; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.inline.InlineRefactoringActionHandler; import com.intellij.refactoring.rename.RenameProcessor; import com.intellij.testFramework.*; @@ -1284,8 +1286,7 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { ((EditorImpl)myEditor).getScrollPane().getViewport().setViewPosition(viewPosition); ((EditorImpl)myEditor).getScrollPane().getViewport().setExtentSize(new Dimension(100, ((EditorImpl)myEditor).getPreferredHeight() - viewPosition.y)); - ProperTextRange visibleRange = VisibleHighlightingPassFactory.calculateVisibleRange(getEditor()); - return visibleRange; + return VisibleHighlightingPassFactory.calculateVisibleRange(getEditor()); } @@ -2181,5 +2182,45 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { private boolean daemonIsWorkingOrPending() { return PsiDocumentManager.getInstance(myProject).isUncommited(myEditor.getDocument()) || myDaemonCodeAnalyzer.isRunningOrPending(); } + + public void testRehighlightInDebuggerExpressionFragment() throws Exception { + PsiExpressionCodeFragment fragment = JavaCodeFragmentFactory.getInstance(getProject()).createExpressionCodeFragment("+ \"a\"", null, + PsiType.getJavaLangObject(getPsiManager(), GlobalSearchScope.allScope(getProject())), true); + myFile = fragment; + Document document = PsiDocumentManager.getInstance(getProject()).getDocument(fragment); + myEditor = EditorFactory.getInstance().createEditor(document, getProject(), StdFileTypes.JAVA, false); + + ProperTextRange visibleRange = makeEditorWindowVisible(new Point(0, 0)); + assertEquals(document.getTextLength(), visibleRange.getLength()); + + try { + final EditorInfo editorInfo = new EditorInfo(document.getText()); + + final String newFileText = editorInfo.getNewFileText(); + ApplicationManager.getApplication().runWriteAction(() -> { + if (!document.getText().equals(newFileText)) { + document.setText(newFileText); + } + + editorInfo.applyToEditor(myEditor); + }); + + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + + + List errors = highlightErrors(); + HighlightInfo error = assertOneElement(errors); + assertEquals("Operator '+' cannot be applied to 'java.lang.String'", error.getDescription()); + + type(" "); + + Collection afterTyping = highlightErrors(); + HighlightInfo after = assertOneElement(afterTyping); + assertEquals("Operator '+' cannot be applied to 'java.lang.String'", after.getDescription()); + } + finally { + EditorFactory.getInstance().releaseEditor(myEditor); + } + } } diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java index 6a3a08b38b1d..cfddc716f0a3 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -44,10 +44,7 @@ import com.intellij.openapi.util.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.problems.Problem; import com.intellij.problems.WolfTheProblemSolver; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiErrorElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; +import com.intellij.psi.*; import com.intellij.psi.search.PsiTodoSearchHelper; import com.intellij.psi.search.TodoItem; import com.intellij.psi.util.PsiUtilCore; @@ -199,8 +196,8 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP List outsideRanges = new ArrayList(); Divider.divideInsideAndOutside(getFile(), myRestrictRange.getStartOffset(), myRestrictRange.getEndOffset(), myPriorityRange, insideElements, insideRanges, outsideElements, outsideRanges, false, SHOULD_HIGHLIGHT_FILTER); - // put file element always in outsideElements - if (!insideElements.isEmpty() && insideElements.get(insideElements.size()-1) instanceof PsiFile) { + // put file element always in outsideElements (except file fragments where they have crazy element ranges: an expression might be an immediate child of a file there) + if (!insideElements.isEmpty() && insideElements.get(insideElements.size()-1) instanceof PsiFile && !(insideElements.get(insideElements.size()-1) instanceof PsiCodeFragment)) { PsiElement file = insideElements.remove(insideElements.size() - 1); outsideElements.add(file); ProperTextRange range = insideRanges.remove(insideRanges.size() - 1); @@ -432,7 +429,6 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP @NotNull final Project project) throws ProcessCanceledException { progress.cancel(); JobScheduler.getScheduler().schedule(new Runnable() { - @Override public void run() { Application application = ApplicationManager.getApplication(); diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java index 4ae0f8a6ea1c..36c2c1e007e4 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -188,9 +188,9 @@ public class UpdateHighlightersUtil { if (!info.isFromInjection() && hiEnd < document.getTextLength() && (hiEnd <= startOffset || hiStart >= endOffset)) { return true; // injections are oblivious to restricting range } - boolean toRemove = !(hiEnd == document.getTextLength() && - priorityRange.getEndOffset() == document.getTextLength()) && - !priorityRange.containsRange(hiStart, hiEnd); + boolean toRemove = infos.contains(info) || + !priorityRange.containsRange(hiStart, hiEnd) && + (hiEnd != document.getTextLength() || priorityRange.getEndOffset() != document.getTextLength()); if (toRemove) { infosToRemove.recycleHighlighter(highlighter); info.highlighter = null;