Merge remote-tracking branch 'origin/master'

This commit is contained in:
Anton Tarasov
2016-01-14 18:12:46 +03:00
40 changed files with 653 additions and 631 deletions
@@ -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<PsiElement, PsiElement>() {
@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 {
@@ -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);
}
@@ -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 {
@@ -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<PsiClassHolderFileStub>
try {
StubBuildingVisitor<VirtualFile> visitor = new StubBuildingVisitor<VirtualFile>(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<PsiClassHolderFileStub>
public void accept(VirtualFile innerClass, StubBuildingVisitor<VirtualFile> 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];
}
@@ -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<Pair<String, String[]>> parseTypeParametersDeclaration(CharacterIterator signature, Function<String, String> mapping) throws ClsFormatException {
if (signature.current() != '<') {
return Collections.emptyList();
}
return list;
List<Pair<String, String[]>> 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<String, String[]> parseTypeParameter(CharacterIterator signature, Function<String, String> 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<String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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;
}
}
}
@@ -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<T> 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 = "<clinit>";
private static final String SYNTHETIC_INIT_METHOD = "<init>";
private static final int ASM_API = Opcodes.ASM5;
private final T mySource;
private final InnerClassSourceStrategy<T> myInnersStrategy;
private final StubElement myParent;
private final int myAccess;
private final String myShortName;
private final Function<String, String> myMapping;
private String myInternalName;
private PsiClassStub myResult;
private PsiModifierListStub myModList;
@@ -77,6 +85,9 @@ public class StubBuildingVisitor<T> extends ClassVisitor {
myParent = parent;
myAccess = access;
myShortName = shortName;
Map<String, Pair<String, String>> mapping = loadMapping(classSource);
myMapping = mapping != null ? createMapping(mapping) : GUESSING_MAPPER;
}
public PsiClassStub<?> getResult() {
@@ -97,7 +108,6 @@ public class StubBuildingVisitor<T> 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<T> 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<String> convertedInterfaces = new ArrayList<String>();
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<String, String[]> 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<String, String>() {
@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<T> extends ClassVisitor {
new PsiClassReferenceListStubImpl(type, parent, types, role);
}
@Nullable
private static String parseClassDescription(String superName, String[] interfaces, List<String> 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<String> 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<T> extends ClassVisitor {
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return new AnnotationTextCollector(desc, new Consumer<String>() {
return new AnnotationTextCollector(desc, myMapping, new Consumer<String>() {
@Override
public void consume(String text) {
new PsiAnnotationStubImpl(myModList, text);
@@ -265,9 +271,8 @@ public class StubBuildingVisitor<T> 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<T> 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<T> 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<String> args = new ArrayList<String>();
List<String> throwables = exceptions != null ? new ArrayList<String>() : 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<String, String[]> 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<String> 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<T> 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<String> 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<String> 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<String> args,
@Nullable List<String> 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<String, String>() {
@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<Type, String>() {
@Override
public String fun(Type type) {
return toJavaType(type, myMapping);
}
});
result.throwTypes = exceptions == null ? null : ContainerUtil.map(exceptions, new Function<String, String>() {
@Override
public String fun(String name) {
return myMapping.fun(name);
}
});
return result;
}
private static class ClassInfo {
private List<Pair<String, String[]>> typeParameters;
private String superName;
private List<String> interfaceNames;
}
private static class MethodInfo {
private List<Pair<String, String[]>> typeParameters;
private String returnType;
private List<String> argTypes;
private List<String> throwTypes;
}
private static class AnnotationTextCollector extends AnnotationVisitor {
private final StringBuilder myBuilder = new StringBuilder();
private final Function<String, String> myMapping;
private final Consumer<String> myCallback;
private boolean hasPrefix = false;
private boolean hasParams = false;
private final String myDesc;
public AnnotationTextCollector(@Nullable String desc, Consumer<String> callback) {
public AnnotationTextCollector(@Nullable String desc, Function<String, String> mapping, Consumer<String> 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<T> extends ClassVisitor {
@Override
public AnnotationVisitor visitAnnotation(String name, String desc) {
valuePairPrefix(name);
return new AnnotationTextCollector(desc, new Consumer<String>() {
return new AnnotationTextCollector(desc, myMapping, new Consumer<String>() {
@Override
public void consume(String text) {
myBuilder.append(text);
@@ -518,7 +533,7 @@ public class StubBuildingVisitor<T> extends ClassVisitor {
public AnnotationVisitor visitArray(String name) {
valuePairPrefix(name);
myBuilder.append('{');
return new AnnotationTextCollector(null, new Consumer<String>() {
return new AnnotationTextCollector(null, myMapping, new Consumer<String>() {
@Override
public void consume(String text) {
myBuilder.append(text).append('}');
@@ -528,7 +543,7 @@ public class StubBuildingVisitor<T> 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<T> extends ClassVisitor {
private static class AnnotationCollectingVisitor extends FieldVisitor {
private final PsiModifierListStub myModList;
private final Function<String, String> myMapping;
private AnnotationCollectingVisitor(PsiModifierListStub modList) {
private AnnotationCollectingVisitor(PsiModifierListStub modList, Function<String, String> mapping) {
super(ASM_API);
myModList = modList;
myMapping = mapping;
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return new AnnotationTextCollector(desc, new Consumer<String>() {
return new AnnotationTextCollector(desc, myMapping, new Consumer<String>() {
@Override
public void consume(String text) {
new PsiAnnotationStubImpl(myModList, text);
@@ -561,15 +578,17 @@ public class StubBuildingVisitor<T> extends ClassVisitor {
private final int myParamIgnoreCount;
private final int myParamCount;
private final PsiParameterStubImpl[] myParamStubs;
private final Function<String, String> 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<String, String> mapping) {
super(ASM_API);
myOwner = owner;
myModList = modList;
@@ -577,11 +596,12 @@ public class StubBuildingVisitor<T> extends ClassVisitor {
myParamIgnoreCount = paramIgnoreCount;
myParamCount = paramCount;
myParamStubs = paramStubs;
myMapping = mapping;
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return new AnnotationTextCollector(desc, new Consumer<String>() {
return new AnnotationTextCollector(desc, myMapping, new Consumer<String>() {
@Override
public void consume(String text) {
new PsiAnnotationStubImpl(myModList, text);
@@ -591,7 +611,7 @@ public class StubBuildingVisitor<T> extends ClassVisitor {
@Override
public AnnotationVisitor visitAnnotationDefault() {
return new AnnotationTextCollector(null, new Consumer<String>() {
return new AnnotationTextCollector(null, myMapping, new Consumer<String>() {
@Override
public void consume(String text) {
((PsiMethodStubImpl)myOwner).setDefaultValueText(text);
@@ -614,22 +634,14 @@ public class StubBuildingVisitor<T> 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<String>() {
return parameter < myParamIgnoreCount ? null : new AnnotationTextCollector(desc, myMapping, new Consumer<String>() {
@Override
public void consume(String text) {
new PsiAnnotationStubImpl(myOwner.findParameter(parameter - myParamIgnoreCount).getModList(), text);
@@ -639,7 +651,7 @@ public class StubBuildingVisitor<T> 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<String, String> mapping) {
if (value == null) return null;
if (value instanceof String) {
@@ -700,31 +712,98 @@ public class StubBuildingVisitor<T> 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<String, String> 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<String, Pair<String, String>> loadMapping(Object classSource) {
if (MAP_INNER_CLASSES_BY_TABLE && classSource instanceof VirtualFile) {
try {
final Map<String, Pair<String, String>> 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<String, String> createMapping(final Map<String, Pair<String, String>> mapping) {
return new Function<String, String>() {
@Override
public String fun(String internalName) {
String className = internalName;
if (className.indexOf('$') >= 0) {
Pair<String, String> 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<String, String> GUESSING_MAPPER = new Function<String, String>() {
@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('/', '.');
}
};
}
@@ -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<PsiMethod> 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<String> args,
@Nullable List<String> 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<PsiMethod> 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);
@@ -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("+ <caret>\"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<HighlightInfo> errors = highlightErrors();
HighlightInfo error = assertOneElement(errors);
assertEquals("Operator '+' cannot be applied to 'java.lang.String'", error.getDescription());
type(" ");
Collection<HighlightInfo> afterTyping = highlightErrors();
HighlightInfo after = assertOneElement(afterTyping);
assertEquals("Operator '+' cannot be applied to 'java.lang.String'", after.getDescription());
}
finally {
EditorFactory.getInstance().releaseEditor(myEditor);
}
}
}
@@ -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<?,P>", SignatureParsing.parseTypeString(new StringCharacterIterator("LPsi<*TP>;")));
assertEquals("Psi<? extends P>", SignatureParsing.parseTypeString(new StringCharacterIterator("LPsi<+TP>;")));
assertEquals("Psi<? super P>", SignatureParsing.parseTypeString(new StringCharacterIterator("LPsi<-TP>;")));
parseTypeString("Psi<?,P>", "LPsi<*TP>;");
parseTypeString("Psi<? extends P>", "LPsi<+TP>;");
parseTypeString("Psi<? super P>", "LPsi<-TP>;");
}
}
@Test
public void testMapping() throws ClsFormatException {
parseTypeString("p.Obj.I<p.Obj1.I,p.Obj2.I>", "Lp/Obj$I<Lp/Obj1$I;Lp/Obj2$I;>;");
parseTypeString("p.Obj$.I<p.$Obj1.I,p.Obj2.I$>", "Lp/Obj$$I<Lp/$Obj1$I;Lp/Obj2$I$;>;");
}
private static void parseTypeString(String expected, String signature) throws ClsFormatException {
assertEquals(expected, SignatureParsing.parseTypeString(new StringCharacterIterator(signature), StubBuildingVisitor.GUESSING_MAPPER));
}
}
@@ -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<ProperTextRange> outsideRanges = new ArrayList<ProperTextRange>();
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();
@@ -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;
@@ -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();
}
@@ -782,6 +782,27 @@ public class DiffUtil {
return Math.max(document.getLineCount(), 1);
}
@NotNull
public static List<String> getLines(@NotNull Document document) {
return getLines(document, 0, getLineCount(document));
}
@NotNull
public static List<String> 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<String> result = new ArrayList<String>();
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
//
@@ -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<TemplatePreprocessor> EP_NAME = ExtensionPointName.create("com.intellij.liveTemplatePreprocessor");
@@ -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<FoldRegion> myRegionsToRestore = new ArrayList<FoldRegion>();
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);
}
}
}
}
@@ -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
*
@@ -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();
}
@@ -103,7 +103,7 @@ import java.util.List;
* <ul>
* <li>Left free painters</li>
* <li>Icons</li>
* <li>Debugger additional area</li>
* <li>Gap (required by debugger to set breakpoints with mouse click - IDEA-137353) </li>
* <li>Free painters</li>
* </ul>
* </li>
@@ -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;
}
@@ -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<UpdateChannel> = 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<BuildInfo> {
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<BuildInfo> {
}
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
@@ -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() {
@@ -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;
@@ -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
@@ -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(" ");
@@ -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) {
@@ -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
@@ -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;
}
@@ -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
@@ -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<String> getLines() {
return getLines(0, getLineCount(myDocument) - 1);
}
@NotNull
public List<String> getLines(int from, int to) {
ArrayList<String> result = new ArrayList<String>();
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);
}
}
@@ -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<String> lines = new DocumentWrapper(myDocument).getLines(changedLine1, changedLine2 - 1);
List<String> vcsLines = new DocumentWrapper(myVcsDocument).getLines(vcsLine1, vcsLine2 - 1);
List<String> lines = DiffUtil.getLines(myDocument, changedLine1, changedLine2);
List<String> 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<Range> rangesAfterChange, int shift) {
@@ -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<Range> 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<String> current,
@NotNull List<String> vcs,
int shift,
int vcsShift,
@NotNull LineStatusTracker.Mode mode)
throws FilesTooBigForDiffException {
myRanges = new LinkedList<Range>();
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<Range> createRanges(@NotNull Document current, @NotNull Document vcs) throws FilesTooBigForDiffException {
return createRanges(current, vcs, false);
}
@NotNull
public List<Range> getRanges() {
return myRanges;
public static List<Range> 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<String> current,
@NotNull List<String> vcs,
int shift,
int vcsShift) throws FilesTooBigForDiffException {
@NotNull
public static List<Range> createRanges(@NotNull List<String> current,
@NotNull List<String> vcs,
int shift,
int vcsShift,
boolean innerWhitespaceChanges) throws FilesTooBigForDiffException {
Diff.Change ch = Diff.buildChanges(ArrayUtil.toStringArray(vcs), ArrayUtil.toStringArray(current));
List<Range> result = new ArrayList<Range>();
while (ch != null) {
Range range = createOn(ch, shift, vcsShift);
myRanges.add(range);
ch = ch.link;
}
}
private void processSmart(@NotNull List<String> current,
@NotNull List<String> 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) {
@@ -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<CandidateInfo> traitFields = new TraitProcessor<PsiField>(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<Collection<TraitFieldDescriptor>> descriptors = FileBasedIndex.getInstance().getValues(
INDEX_ID,
FileBasedIndex.getFileId(virtualFile),
FileBasedIndex.getFileId(helperFile),
trait.getResolveScope()
);
for (Collection<TraitFieldDescriptor> traitFieldDescriptors : descriptors) {
@@ -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<Collection<TraitFieldDescriptor>> {
public static final ID<Integer, Collection<TraitFieldDescriptor>> 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<Integer, Collection<TraitFieldDescriptor>> mapInner(@NotNull FileContent inputData) {
final int key = FileBasedIndex.getFileId(inputData.getFile());
final Map<Integer, Collection<TraitFieldDescriptor>> 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<Boolean, String> 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;
}
@@ -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
@@ -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
+4 -1
View File
@@ -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"
@@ -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);
@@ -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;
@@ -0,0 +1 @@
print("%d%s%s" % (((1,) + <caret>("", ""))))
@@ -0,0 +1 @@
print("%d%s%s" % ((1,) + ("", "")))
@@ -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);