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 { 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..72017210db58 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,24 +78,16 @@ 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) { Logger.getInstance(ClassFileViewProvider.class).warn(file.getPath(), e); } 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/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 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/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/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/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; 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(); } 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/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"); 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); + } } } } 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 * 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(); } 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 a7192633f843..aaf8db2e7fd3 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; } 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 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; 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 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-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) { 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/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; } 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/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 9177842c6680..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); } @@ -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(); + } } } } @@ -622,10 +628,10 @@ 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(); + 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 6b795a294873..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 @@ -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; @@ -25,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(new DocumentWrapper(current).getLines(), new DocumentWrapper(vcs).getLines(), 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) { 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 e48a87c9c172..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 @@ -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; @@ -53,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); } }; @@ -123,8 +129,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 +139,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 +158,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 +185,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; } 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 diff --git a/python/build/pycharm_community_build.gant b/python/build/pycharm_community_build.gant index d5d6f2a84f61..9241b5cd2a4c 100644 --- a/python/build/pycharm_community_build.gant +++ b/python/build/pycharm_community_build.gant @@ -178,7 +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-${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" 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); 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);