mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote branch 'origin/master'
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.compiler;
|
||||
|
||||
import com.intellij.compiler.make.CacheCorruptedException;
|
||||
import com.intellij.compiler.make.CachingSearcher;
|
||||
import com.intellij.openapi.compiler.CompileContext;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
|
||||
@@ -25,5 +27,5 @@ import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
public interface DependencyProcessor {
|
||||
ExtensionPointName<DependencyProcessor> EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.compiler.makeDependencyProcessor");
|
||||
|
||||
void processDependencies(CompileContext context, int classQualifiedName);
|
||||
void processDependencies(CompileContext context, int classQualifiedName, CachingSearcher searcher) throws CacheCorruptedException;
|
||||
}
|
||||
|
||||
@@ -429,7 +429,7 @@ public class DependencyCache {
|
||||
}
|
||||
changedRetentionPolicyDependencyProcessor.checkAnnotationRetentionPolicyChanges(qName);
|
||||
for (DependencyProcessor additionalProcessor : DependencyProcessor.EXTENSION_POINT_NAME.getExtensions()) {
|
||||
additionalProcessor.processDependencies(context, qName);
|
||||
additionalProcessor.processDependencies(context, qName, searcher);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Collection;
|
||||
|
||||
public class BreakpointChooser {
|
||||
@@ -149,7 +150,7 @@ public class BreakpointChooser {
|
||||
};
|
||||
setSelectedBreakpoint(baseBreakpoint);
|
||||
myActionToolbar = ActionManager.getInstance().createActionToolbar("asdad", new DefaultActionGroup(myComboBoxAction), true);
|
||||
|
||||
myActionToolbar.setLayoutPolicy(ActionToolbar.WRAP_LAYOUT_POLICY);
|
||||
}
|
||||
|
||||
public void setBreakpointItems(Collection<BreakpointItem> items) {
|
||||
|
||||
+1
-1
@@ -570,7 +570,7 @@ public abstract class BreakpointPropertiesPanel {
|
||||
PsiElement context = breakpoint.getEvaluationElement();
|
||||
myPassCountCheckbox.setSelected(breakpoint.COUNT_FILTER_ENABLED);
|
||||
|
||||
myConditionCheckbox.setSelected(breakpoint.CONDITION_ENABLED);
|
||||
myConditionCheckbox.setSelected(breakpoint.CONDITION_ENABLED || breakpoint.getCondition() == null || breakpoint.getCondition().isEmpty());
|
||||
|
||||
myConditionCombo.setEnabled(myBreakpoint.CONDITION_ENABLED);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.ide.actions;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.highlighter.ProjectFileType;
|
||||
import com.intellij.ide.impl.ProjectUtil;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
@@ -76,6 +77,6 @@ public class OpenProjectAction extends AnAction implements DumbAware {
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
super.update(e);
|
||||
e.getPresentation().setVisible(false);
|
||||
e.getPresentation().setVisible(ActionPlaces.WELCOME_SCREEN.equals(e.getPlace()));
|
||||
}
|
||||
}
|
||||
@@ -163,7 +163,6 @@ public class ModulesConfigurator implements ModulesProvider, ModuleEditor.Change
|
||||
}
|
||||
};
|
||||
|
||||
myModuleEditors.add(moduleEditor);
|
||||
myModuleEditors.add(moduleEditor);
|
||||
|
||||
moduleEditor.addChangeListener(this);
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceE
|
||||
final PsiModifierListOwner parent = PsiTreeUtil.getParentOfType(elementAt, PsiModifierListOwner.class, false, PsiCodeBlock.class);
|
||||
if (parent != null) {
|
||||
for (PsiMethod m : ((PsiClass)item.getObject()).getMethods()) {
|
||||
if (!(m instanceof PsiAnnotationMethod)) continue;
|
||||
if (!PsiUtil.isAnnotationMethod(m)) continue;
|
||||
final PsiAnnotationMemberValue defaultValue = ((PsiAnnotationMethod)m).getDefaultValue();
|
||||
if (defaultValue == null) return true;
|
||||
}
|
||||
|
||||
+13
-4
@@ -145,10 +145,19 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
|
||||
if (psiElement().inside(PsiAnnotationParameterList.class).accepts(position)) {
|
||||
return new OrFilter(new ClassFilter(PsiAnnotationMethod.class),
|
||||
ElementClassFilter.CLASS,
|
||||
ElementClassFilter.PACKAGE_FILTER,
|
||||
new AndFilter(new ClassFilter(PsiField.class), new ModifierFilter(PsiModifier.STATIC, PsiModifier.FINAL)));
|
||||
OrFilter orFilter = new OrFilter(ElementClassFilter.CLASS,
|
||||
ElementClassFilter.PACKAGE_FILTER,
|
||||
new AndFilter(new ClassFilter(PsiField.class),
|
||||
new ModifierFilter(PsiModifier.STATIC, PsiModifier.FINAL)));
|
||||
if (psiElement().insideStarting(psiNameValuePair()).accepts(position)) {
|
||||
orFilter.addFilter(new ClassFilter(PsiAnnotationMethod.class) {
|
||||
@Override
|
||||
public boolean isAcceptable(Object element, PsiElement context) {
|
||||
return element instanceof PsiAnnotationMethod && PsiUtil.isAnnotationMethod((PsiElement)element);
|
||||
}
|
||||
});
|
||||
}
|
||||
return orFilter;
|
||||
}
|
||||
|
||||
if (psiElement().afterLeaf("=").inside(PsiVariable.class).accepts(position)) {
|
||||
|
||||
@@ -135,6 +135,7 @@ public class JavaCompletionData extends JavaAwareCompletionData {
|
||||
and(JavaSmartCompletionContributor.INSIDE_EXPRESSION,
|
||||
not(psiElement().afterLeaf(PsiKeyword.CASE)),
|
||||
not(psiElement().afterLeaf(psiElement().withText(".").afterLeaf(PsiKeyword.THIS, PsiKeyword.SUPER))),
|
||||
not(psiElement().inside(PsiAnnotation.class)),
|
||||
not(START_SWITCH));
|
||||
|
||||
public static final AndFilter CLASS_START = new AndFilter(
|
||||
@@ -142,7 +143,8 @@ public class JavaCompletionData extends JavaAwareCompletionData {
|
||||
END_OF_BLOCK,
|
||||
new PatternFilter(psiElement().afterLeaf(
|
||||
or(
|
||||
psiElement().withoutText(".").inside(psiElement(PsiModifierList.class).withParent(not(psiElement(PsiParameter.class)))),
|
||||
psiElement().withoutText(".").inside(psiElement(PsiModifierList.class).withParent(not(psiElement(PsiParameter.class)))).andNot(
|
||||
psiElement().inside(PsiAnnotationParameterList.class)),
|
||||
psiElement().isNull())))
|
||||
),
|
||||
new PatternFilter(not(psiElement().afterLeaf("@"))));
|
||||
@@ -486,8 +488,10 @@ public class JavaCompletionData extends JavaAwareCompletionData {
|
||||
}
|
||||
|
||||
if (EXPR_KEYWORDS.accepts(position)) {
|
||||
result.addElement(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.NEW), TailType.INSERT_SPACE));
|
||||
result.addElement(createKeyword(position, PsiKeyword.NULL));
|
||||
if (PsiTreeUtil.getParentOfType(position, PsiAnnotation.class) == null) {
|
||||
result.addElement(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.NEW), TailType.INSERT_SPACE));
|
||||
result.addElement(createKeyword(position, PsiKeyword.NULL));
|
||||
}
|
||||
result.addElement(createKeyword(position, PsiKeyword.TRUE));
|
||||
result.addElement(createKeyword(position, PsiKeyword.FALSE));
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PropertyUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -150,7 +151,7 @@ public class PreferByKindWeigher extends LookupElementWeigher {
|
||||
return MyResult.classLiteral;
|
||||
}
|
||||
|
||||
if (object instanceof PsiAnnotationMethod && ((PsiAnnotationMethod)object).getContainingClass().isAnnotationType()) {
|
||||
if (object instanceof PsiMethod && PsiUtil.isAnnotationMethod((PsiElement)object)) {
|
||||
return MyResult.annoMethod;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -188,7 +188,7 @@ public class AnnotationsHighlightUtil {
|
||||
PsiMethod[] annotationMethods = aClass.getMethods();
|
||||
List<String> missed = new ArrayList<String>();
|
||||
for (PsiMethod method : annotationMethods) {
|
||||
if (method instanceof PsiAnnotationMethod) {
|
||||
if (PsiUtil.isAnnotationMethod(method)) {
|
||||
PsiAnnotationMethod annotationMethod = (PsiAnnotationMethod)method;
|
||||
if (annotationMethod.getDefaultValue() == null) {
|
||||
if (!names.contains(annotationMethod.getName())) {
|
||||
@@ -216,7 +216,7 @@ public class AnnotationsHighlightUtil {
|
||||
@Nullable
|
||||
public static HighlightInfo checkConstantExpression(PsiExpression expression) {
|
||||
final PsiElement parent = expression.getParent();
|
||||
if (parent instanceof PsiAnnotationMethod || parent instanceof PsiNameValuePair || parent instanceof PsiArrayInitializerMemberValue) {
|
||||
if (PsiUtil.isAnnotationMethod(parent) || parent instanceof PsiNameValuePair || parent instanceof PsiArrayInitializerMemberValue) {
|
||||
if (!PsiUtil.isConstantExpression(expression)) {
|
||||
return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, JavaErrorMessages.message("annotation.nonconstant.attribute.value"));
|
||||
}
|
||||
@@ -312,7 +312,7 @@ public class AnnotationsHighlightUtil {
|
||||
}
|
||||
|
||||
public static HighlightInfo checkAnnotationDeclaration(final PsiElement parent, final PsiReferenceList list) {
|
||||
if (parent instanceof PsiAnnotationMethod) {
|
||||
if (PsiUtil.isAnnotationMethod(parent)) {
|
||||
PsiAnnotationMethod method = (PsiAnnotationMethod)parent;
|
||||
if (list == method.getThrowsList()) {
|
||||
return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, list, JavaErrorMessages.message("annotation.members.may.not.have.throws.list"));
|
||||
|
||||
+1
-1
@@ -925,7 +925,7 @@ public class GenericsHighlightUtil {
|
||||
parameterList,
|
||||
JavaErrorMessages.message("generics.enum.may.not.have.type.parameters"));
|
||||
}
|
||||
if (parent instanceof PsiAnnotationMethod) {
|
||||
if (PsiUtil.isAnnotationMethod(parent)) {
|
||||
return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parameterList, JavaErrorMessages.message("generics.annotation.members.may.not.have.type.parameters"));
|
||||
}
|
||||
else if (parent instanceof PsiClass && ((PsiClass)parent).isAnnotationType()) {
|
||||
|
||||
@@ -2537,7 +2537,7 @@ public class HighlightUtil {
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkAnnotationMethodParameters(@NotNull PsiParameterList list) {
|
||||
if (list.getParent() instanceof PsiAnnotationMethod && list.getParametersCount() > 0) {
|
||||
if (PsiUtil.isAnnotationMethod(list.getParent()) && list.getParametersCount() > 0) {
|
||||
final String message = JavaErrorMessages.message("annotation.interface.members.may.not.have.parameters");
|
||||
return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, list, message);
|
||||
}
|
||||
|
||||
+1
-1
@@ -190,7 +190,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
if (parent instanceof PsiNameValuePair) {
|
||||
method = (PsiMethod)parent.getReference().resolve();
|
||||
}
|
||||
else if (parent instanceof PsiAnnotationMethod) {
|
||||
else if (PsiUtil.isAnnotationMethod(parent)) {
|
||||
method = (PsiMethod)parent;
|
||||
}
|
||||
if (method != null) {
|
||||
|
||||
+808
-808
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.lang.parameterInfo.*;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -122,6 +123,6 @@ public class AnnotationParameterInfoHandler implements ParameterInfoHandler<PsiA
|
||||
if (pair == null) return null;
|
||||
final PsiReference reference = pair.getReference();
|
||||
final PsiElement resolved = reference != null ? reference.resolve():null;
|
||||
return resolved instanceof PsiAnnotationMethod ? (PsiAnnotationMethod)resolved : null;
|
||||
return PsiUtil.isAnnotationMethod(resolved) ? (PsiAnnotationMethod)resolved : null;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -78,7 +78,12 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
|
||||
}
|
||||
}
|
||||
}
|
||||
if (importList.findSingleImportStatement(refExpr.getReferenceName()) == null) {
|
||||
final PsiImportStatementBase importStatement = importList.findSingleImportStatement(refExpr.getReferenceName());
|
||||
if (importStatement == null) {
|
||||
return qName;
|
||||
}
|
||||
final PsiElement resolve = importStatement.resolve();
|
||||
if (resolve instanceof PsiMember && ((PsiMember)resolve).getContainingClass() != aClass) {
|
||||
return qName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.search.UsageSearchContext;
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -37,7 +38,7 @@ public class MethodUsagesSearcher extends QueryExecutorBase<PsiReference, Method
|
||||
processConstructorReferences(consumer, method, searchScope, !strictSignatureSearch, strictSignatureSearch, collector);
|
||||
}
|
||||
|
||||
if (method instanceof PsiAnnotationMethod &&
|
||||
if (PsiUtil.isAnnotationMethod(method) &&
|
||||
PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(method.getName()) &&
|
||||
method.getParameterList().getParametersCount() == 0) {
|
||||
ReferencesSearch.search(method.getContainingClass(), p.getScope()).forEach(PsiAnnotationMethodReferencesSearcher.createImplicitDefaultAnnotationMethodConsumer(
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ package com.intellij.psi.impl.search;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.Query;
|
||||
import com.intellij.util.QueryExecutor;
|
||||
@@ -15,7 +16,7 @@ public class PsiAnnotationMethodReferencesSearcher implements QueryExecutor<PsiR
|
||||
@Override
|
||||
public boolean execute(@NotNull final ReferencesSearch.SearchParameters p, @NotNull final Processor<PsiReference> consumer) {
|
||||
final PsiElement refElement = p.getElementToSearch();
|
||||
if (refElement instanceof PsiAnnotationMethod) {
|
||||
if (PsiUtil.isAnnotationMethod(refElement)) {
|
||||
PsiMethod method = (PsiMethod)refElement;
|
||||
if (PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(method.getName()) && method.getParameterList().getParametersCount() == 0) {
|
||||
final Query<PsiReference> query = ReferencesSearch.search(method.getContainingClass(), p.getScope(), p.isIgnoreAccessScope());
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -29,6 +30,8 @@ import java.util.List;
|
||||
* Date: 7/17/12
|
||||
*/
|
||||
public class LambdaUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#" + LambdaUtil.class.getName());
|
||||
|
||||
@Nullable
|
||||
public static String checkInterfaceFunctional(@NotNull PsiClass psiClass) {
|
||||
final List<MethodSignature> signatures = findFunctionCandidates(psiClass);
|
||||
@@ -120,7 +123,14 @@ public class LambdaUtil {
|
||||
if (methodSignature != null) {
|
||||
final PsiType[] types = methodSignature.getParameterTypes();
|
||||
if (parameterIndex < types.length) {
|
||||
return resolveResult.getSubstitutor().substitute(types[parameterIndex]);
|
||||
final PsiType psiType = resolveResult.getSubstitutor().substitute(types[parameterIndex]);
|
||||
if (psiType instanceof PsiWildcardType) {
|
||||
final PsiType bound = ((PsiWildcardType)psiType).getBound();
|
||||
if (bound != null) {
|
||||
return bound;
|
||||
}
|
||||
}
|
||||
return psiType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,6 +150,10 @@ public class LambdaUtil {
|
||||
else if (parent instanceof PsiVariable) {
|
||||
type = ((PsiVariable)parent).getType();
|
||||
}
|
||||
else if (parent instanceof PsiAssignmentExpression) {
|
||||
final PsiExpression lExpression = ((PsiAssignmentExpression)parent).getLExpression();
|
||||
type = lExpression.getType();
|
||||
}
|
||||
else if (parent instanceof PsiExpressionList) {
|
||||
final PsiExpressionList expressionList = (PsiExpressionList)parent;
|
||||
final int lambdaIdx = ArrayUtil.find(expressionList.getExpressions(), lambdaExpression);
|
||||
@@ -173,7 +187,8 @@ public class LambdaUtil {
|
||||
|
||||
public static boolean isAcceptable(PsiLambdaExpression lambdaExpression, final PsiType leftType) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(leftType);
|
||||
final MethodSignature methodSignature = getFunction(resolveResult.getElement());
|
||||
final PsiClass psiClass = resolveResult.getElement();
|
||||
final MethodSignature methodSignature = getFunction(psiClass);
|
||||
if (methodSignature == null) return false;
|
||||
final PsiParameter[] lambdaParameters = lambdaExpression.getParameterList().getParameters();
|
||||
final PsiType[] parameterTypes = methodSignature.getParameterTypes();
|
||||
@@ -182,11 +197,57 @@ public class LambdaUtil {
|
||||
PsiParameter parameter = lambdaParameters[lambdaParamIdx];
|
||||
final PsiTypeElement typeElement = parameter.getTypeElement();
|
||||
if (typeElement != null) {
|
||||
if (!typeElement.getType().equals(resolveResult.getSubstitutor().substitute(parameterTypes[lambdaParamIdx]))) {
|
||||
final PsiType lambdaFormalType = typeElement.getType();
|
||||
final PsiType methodParameterType = parameterTypes[lambdaParamIdx];
|
||||
if (lambdaFormalType instanceof PsiPrimitiveType){
|
||||
if (methodParameterType instanceof PsiPrimitiveType) return methodParameterType.isAssignableFrom(lambdaFormalType);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!resolveResult.getSubstitutor().substitute(methodSignature.getSubstitutor().substitute(methodParameterType)).isAssignableFrom(lambdaFormalType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
PsiMethod method = null;
|
||||
LOG.assertTrue(psiClass != null);
|
||||
final PsiMethod[] methodsByName = psiClass.findMethodsByName(methodSignature.getName(), true);
|
||||
for (PsiMethod psiMethod : methodsByName) {
|
||||
if (MethodSignatureUtil.areSignaturesEqual(getMethodSignature(psiMethod, psiClass, psiMethod.getContainingClass()), methodSignature)) {
|
||||
method = psiMethod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG.assertTrue(method != null);
|
||||
PsiType methodReturnType = method.getReturnType();
|
||||
if (methodReturnType != null && methodReturnType != PsiType.VOID) {
|
||||
methodReturnType = resolveResult.getSubstitutor().substitute(methodSignature.getSubstitutor().substitute(methodReturnType));
|
||||
final PsiElement body = lambdaExpression.getBody();
|
||||
if (body instanceof PsiCodeBlock) {
|
||||
final PsiCodeBlock block = (PsiCodeBlock)body;
|
||||
for (PsiStatement statement : block.getStatements()) {
|
||||
if (statement instanceof PsiReturnStatement) {
|
||||
final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue();
|
||||
if (returnValue != null) {
|
||||
if (!checkReturnTypeAssignability(returnValue.getType(), parameterTypes, lambdaExpression, methodReturnType)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (body instanceof PsiExpression) {
|
||||
return checkReturnTypeAssignability(((PsiExpression)body).getType(), parameterTypes, lambdaExpression, methodReturnType);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean checkReturnTypeAssignability(PsiType lambdaReturnType, PsiType[] parameterTypes, PsiLambdaExpression lambdaExpression, PsiType methodReturnType) {
|
||||
if (lambdaReturnType instanceof PsiLambdaParameterType) {
|
||||
final PsiParameter parameter = ((PsiLambdaParameterType)lambdaReturnType).getParameter();
|
||||
final int parameterIndex = lambdaExpression.getParameterList().getParameterIndex(parameter);
|
||||
if (parameterIndex > -1) {
|
||||
lambdaReturnType = parameterTypes[parameterIndex];
|
||||
}
|
||||
}
|
||||
return lambdaReturnType != null && methodReturnType.isAssignableFrom(lambdaReturnType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,4 +70,8 @@ public class PsiLambdaParameterType extends PsiType {
|
||||
public PsiType[] getSuperTypes() {
|
||||
return PsiType.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
public PsiParameter getParameter() {
|
||||
return myParameter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,6 +690,12 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
return file;
|
||||
}
|
||||
|
||||
public static boolean isAnnotationMethod(PsiElement element) {
|
||||
if (!(element instanceof PsiAnnotationMethod)) return false;
|
||||
PsiClass psiClass = ((PsiAnnotationMethod)element).getContainingClass();
|
||||
return psiClass != null && psiClass.isAnnotationType();
|
||||
}
|
||||
|
||||
private static class TypeParameterIterator implements Iterator<PsiTypeParameter> {
|
||||
private int myIndex;
|
||||
private PsiTypeParameterListOwner myCurrentOwner;
|
||||
|
||||
@@ -96,7 +96,7 @@ public class PsiImplUtil {
|
||||
if (resolved != null) {
|
||||
PsiMethod[] methods = ((PsiClass)resolved).getMethods();
|
||||
for (PsiMethod method : methods) {
|
||||
if (method instanceof PsiAnnotationMethod && Comparing.equal(method.getName(), attributeName)) {
|
||||
if (PsiUtil.isAnnotationMethod(method) && Comparing.equal(method.getName(), attributeName)) {
|
||||
return ((PsiAnnotationMethod)method).getDefaultValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
public class Util {
|
||||
@Foo(val=<caret>) void foo(String[] args) { }
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
interface I1 {
|
||||
void m();
|
||||
}
|
||||
|
||||
interface I2<X> {
|
||||
X m();
|
||||
}
|
||||
|
||||
class Ambiguity1 {
|
||||
|
||||
static void m(I1 i1) {}
|
||||
static <T> void m(I2<T> i2) {}
|
||||
|
||||
{
|
||||
m<error descr="Ambiguous method call: both 'Ambiguity1.m(I1)' and 'Ambiguity1.m(I2<Object>)' match">(()->{throw new AssertionError();})</error>;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
interface I {
|
||||
void m();
|
||||
}
|
||||
|
||||
interface I1 {
|
||||
int m();
|
||||
}
|
||||
|
||||
interface I2 {
|
||||
String m();
|
||||
}
|
||||
|
||||
interface I3<A> {
|
||||
A m();
|
||||
}
|
||||
|
||||
class AmbiguityRawGenerics {
|
||||
|
||||
void foo(I s) { }
|
||||
void foo(I1 s) { }
|
||||
void foo(I2 s) { }
|
||||
<Z> void foo(I3<Z> s) { }
|
||||
|
||||
void bar() {
|
||||
foo<error descr="Ambiguous method call: both 'AmbiguityRawGenerics.foo(I)' and 'AmbiguityRawGenerics.foo(I1)' match">(()-> { throw new RuntimeException(); })</error>;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
interface I {
|
||||
void m();
|
||||
}
|
||||
|
||||
interface I1<A> {
|
||||
void m(A a);
|
||||
}
|
||||
|
||||
interface I2<A> {
|
||||
void m(A a1, A a2);
|
||||
}
|
||||
|
||||
interface IV<A> {
|
||||
void m(A... as);
|
||||
}
|
||||
|
||||
class AmbiguityVarargs {
|
||||
void foo(I s) { }
|
||||
void foo(I1<String> s) { }
|
||||
void foo(I2<String> s) { }
|
||||
void foo(IV<String> s) { }
|
||||
|
||||
void test() {
|
||||
foo(()->{});
|
||||
foo<error descr="Ambiguous method call: both 'AmbiguityVarargs.foo(I1<String>)' and 'AmbiguityVarargs.foo(IV<String>)' match">((a1) -> {})</error>;
|
||||
foo((a1, a2)->{});
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
interface I {
|
||||
void m(int x);
|
||||
}
|
||||
|
||||
interface I1 {
|
||||
int m();
|
||||
}
|
||||
class CastInContexts {
|
||||
void m(I s) { }
|
||||
|
||||
void assignment() {
|
||||
I i1 = (I)(x-> { System.out.println(); });
|
||||
I i2 = (I)((x-> { System.out.println(); }));
|
||||
}
|
||||
|
||||
void method() {
|
||||
m((I)(x-> { System.out.println(); }));
|
||||
}
|
||||
|
||||
I returnContext() {
|
||||
return (I)(x -> { System.out.println(); });
|
||||
}
|
||||
|
||||
{
|
||||
int i = <error descr="Inconvertible types; cannot cast '<lambda expression>' to 'int'">(int) ()-> 1</error>;
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
interface I {
|
||||
void m(int x);
|
||||
}
|
||||
class InContexts {
|
||||
void m(I s) { }
|
||||
|
||||
void assignment() {
|
||||
I s1 = (x-> { System.out.println(); });
|
||||
I s2 = ((x-> { System.out.println(); }));
|
||||
}
|
||||
|
||||
void method() {
|
||||
m((x-> { System.out.println(); }));
|
||||
m(((x-> { System.out.println(); })));
|
||||
}
|
||||
|
||||
I returnContext() {
|
||||
return (x -> {System.out.println();});
|
||||
}
|
||||
}
|
||||
|
||||
interface I1<A, B> {
|
||||
B foo(A a);
|
||||
}
|
||||
class ValueLambdaInContext {
|
||||
|
||||
<Z> void m1(I1<String, Z> i) { }
|
||||
<Z> void m2(I1<String, I1<String, Z>> i) { }
|
||||
|
||||
void exprMethod() {
|
||||
m1(s1 -> 1);
|
||||
m2(s1 -> s2 -> 1);
|
||||
}
|
||||
|
||||
void exprAssignment() {
|
||||
I1<String, Integer> in1 = s1 -> 1;
|
||||
I1<String, I1<String, Integer>> in2 = s1 -> s2 -> 1;
|
||||
}
|
||||
|
||||
void statementMethod() {
|
||||
m1(s1 -> { return 1; });
|
||||
m2(s1 -> { return s2 -> { return 1; }; });
|
||||
}
|
||||
|
||||
void statementAssignment() {
|
||||
I1<String, Integer> in1 = s1 -> { return 1; };
|
||||
I1<String, I1<String, Integer>> in2 = s1 -> { return s2 -> { return 1; }; };
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
interface I<K, V> {
|
||||
public V put(K k, V v);
|
||||
}
|
||||
|
||||
interface A<T>{}
|
||||
interface B<L> extends A<L>{}
|
||||
|
||||
interface SameArgsI<T> {
|
||||
T same(T a, T b);
|
||||
}
|
||||
|
||||
class InferenceFromArgs {
|
||||
|
||||
private static <E> void bar(A<? extends E> a, I<? super E, Integer> i) { }
|
||||
|
||||
void foo(B<Integer> b) {
|
||||
bar(b, (k, v) -> {int i = k; int j = v; return Math.max(i, j);});
|
||||
}
|
||||
|
||||
public static <T> SameArgsI<T> max() {
|
||||
return (a, b) -> b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
interface I<A, B> {
|
||||
B foo(A a);
|
||||
}
|
||||
class NoInferenceResult {
|
||||
|
||||
<A, B> I<A, B> m(I<A, B> f) { return null; }
|
||||
<T> void m1(T t) { }
|
||||
|
||||
void test() {
|
||||
m<error descr="'m(I<java.lang.Object,java.lang.Object>)' in 'NoInferenceResult' cannot be applied to '(<lambda expression>)'">((String s1) -> (String s2) -> s1 + s2)</error>;
|
||||
|
||||
m((String s1) -> s1.length());
|
||||
m((String s1) -> s1);
|
||||
|
||||
m1<error descr="'m1(java.lang.Object)' in 'NoInferenceResult' cannot be applied to '(<lambda expression>)'">(() -> { })</error>;
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
class ReturnTypeIncompatibility {
|
||||
|
||||
interface I1<T extends Number> {
|
||||
T m(Integer x);
|
||||
}
|
||||
|
||||
interface I2<L extends String> {
|
||||
L m(Integer x);
|
||||
}
|
||||
|
||||
interface I3<K> {
|
||||
void m(Integer x);
|
||||
}
|
||||
|
||||
static <P extends Number> void call(I1<P> i1) {
|
||||
i1.m(1);
|
||||
}
|
||||
|
||||
static <P extends String> void call(I2<P> i2) {
|
||||
i2.m(2);
|
||||
}
|
||||
|
||||
static <Q> void call(I3<Q> i3) {
|
||||
i3.m(3);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
call(i-> {return i;});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ReturnTypeCompatibility {
|
||||
|
||||
interface I1<T extends Number> {
|
||||
T m(T x);
|
||||
}
|
||||
|
||||
interface I2<L extends String> {
|
||||
L m(L x);
|
||||
}
|
||||
|
||||
interface I3<K> {
|
||||
void m(K x);
|
||||
}
|
||||
|
||||
static <P extends Number> void call(I1<P> i1) {
|
||||
i1.m(null);
|
||||
}
|
||||
|
||||
static <P extends String> void call(I2<P> i2) {
|
||||
i2.m(null);
|
||||
}
|
||||
|
||||
static <Q> void call(I3<Q> i3) {
|
||||
i3.m(null);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
<error descr="Cannot resolve method 'call(<lambda expression>)'">call</error>(i-> {return i;});
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnTypeChecks1 {
|
||||
|
||||
interface I<K extends Number, V extends Number> {
|
||||
V m(K k);
|
||||
}
|
||||
|
||||
I<Integer, Integer> accepted = i -> { return i; };
|
||||
<error descr="Incompatible types. Found: '<lambda expression>', required: 'ReturnTypeChecks1.I<java.lang.Double,java.lang.Integer>'">I<Double, Integer> rejected = i -> { return i; };</error>
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
class TypeArgsConsistency {
|
||||
|
||||
interface I<T> {
|
||||
T m(int i, int j);
|
||||
}
|
||||
|
||||
static void foo(I<Integer> s) { }
|
||||
|
||||
static <X> I<X> bar(I<X> s) { return null; }
|
||||
|
||||
{
|
||||
I<Integer> i1 = (i, j) -> i + j;
|
||||
foo((i, j) -> i + j);
|
||||
I<Integer> i2 = bar((i, j) -> i + j);
|
||||
I<Integer> i3 = bar<error descr="'bar(TypeArgsConsistency.I<java.lang.Integer>)' in 'TypeArgsConsistency' cannot be applied to '(<lambda expression>)'">((i, j) -> "" + i + j)</error>;
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
class WildcardBounds {
|
||||
|
||||
interface I<T> {
|
||||
T foo(T a, T b);
|
||||
}
|
||||
|
||||
void m1(I<? extends String> f1) {}
|
||||
void m2(I<? super String> f2) {}
|
||||
void m3(I<?> f3) {}
|
||||
|
||||
I<? extends String> f1 = (a, b) -> a;
|
||||
I<? super String> f2 = (a, b) -> a;
|
||||
I<?> f3 = (a, b) -> a;
|
||||
|
||||
{
|
||||
m1((a, b) -> a);
|
||||
m2((a, b) -> a);
|
||||
m3((a, b) -> a);
|
||||
}
|
||||
}
|
||||
+16
@@ -16,4 +16,20 @@ class Foo {
|
||||
bar((int i) -> {System.out.println(i);});
|
||||
}
|
||||
void bar(I i){}
|
||||
}
|
||||
|
||||
class ReturnTypeCompatibility {
|
||||
|
||||
interface I1<L> {
|
||||
L m(L x);
|
||||
}
|
||||
|
||||
static <P> void call(I1<P> i2) {
|
||||
i2.m(null);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
call((String i)->{ return i;});
|
||||
call<error descr="'call(ReturnTypeCompatibility.I1<java.lang.Object>)' in 'ReturnTypeCompatibility' cannot be applied to '(<lambda expression>)'">((int i)->{ return i;})</error>;
|
||||
}
|
||||
}
|
||||
+39
@@ -1,3 +1,5 @@
|
||||
import java.lang.Integer;
|
||||
|
||||
interface I {
|
||||
void m(int i);
|
||||
}
|
||||
@@ -18,6 +20,14 @@ class Foo {
|
||||
<error descr="Incompatible types. Found: 'java.lang.String', required: 'int'">int i = ab;</error>
|
||||
};
|
||||
|
||||
{
|
||||
A<String> a1;
|
||||
a1 = (ab)->{
|
||||
String s = ab;
|
||||
<error descr="Incompatible types. Found: 'java.lang.String', required: 'int'">int i = ab;</error>
|
||||
};
|
||||
}
|
||||
|
||||
A<Integer> bazz() {
|
||||
bar((o) -> {
|
||||
String s = o;
|
||||
@@ -33,3 +43,32 @@ class Foo {
|
||||
void bar(A<String> a){}
|
||||
}
|
||||
|
||||
class CastInference {
|
||||
public interface I1<X> {
|
||||
X m();
|
||||
}
|
||||
public interface I2<X> {
|
||||
X m();
|
||||
}
|
||||
public static <X> void foo(I1<X> s) {}
|
||||
public static <X> void foo(I2<X> s) {}
|
||||
|
||||
public static void main(String[] args) {
|
||||
foo((I1<Integer>)() -> 42);
|
||||
I1<Integer> i1 = (I1<Integer>)() -> 42;
|
||||
}
|
||||
}
|
||||
|
||||
class WildcardBoundsUsage {
|
||||
interface I<X> {
|
||||
boolean foo(X x);
|
||||
}
|
||||
|
||||
public I<Character> bar(I<? super Character> predicate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
{
|
||||
I<Character> i = bar(c -> c.compareTo('x') < 0);
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,8 @@ import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiJavaFile
|
||||
import junit.framework.Test
|
||||
import junit.framework.TestSuite
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
@@ -560,6 +562,7 @@ public interface Test {
|
||||
assert myFixture.editor.caretModel.offset == offset + 1
|
||||
joinAutopopup()
|
||||
joinCompletion()
|
||||
assert !lookup.calculating
|
||||
assertContains "iterable"
|
||||
assertEquals 'iterable', lookup.currentItem.lookupString
|
||||
|
||||
@@ -567,12 +570,14 @@ public interface Test {
|
||||
assert myFixture.editor.caretModel.offset == offset
|
||||
joinAutopopup()
|
||||
joinCompletion()
|
||||
assert !lookup.calculating
|
||||
assertContains "if", "iterable", "int"
|
||||
assertEquals 'iterable', lookup.currentItem.lookupString
|
||||
|
||||
edt { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_LEFT) }
|
||||
joinAutopopup()
|
||||
joinCompletion()
|
||||
assert !lookup.calculating
|
||||
assert lookup.items.size() > 3
|
||||
|
||||
for (i in 0.."iter".size()) {
|
||||
|
||||
+14
@@ -270,6 +270,20 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase {
|
||||
assert "B" in myFixture.lookupElementStrings
|
||||
}
|
||||
|
||||
public void testAnnoParameterValue() throws Exception {
|
||||
configure()
|
||||
def strings = myFixture.lookupElementStrings
|
||||
assert 'AssertionError' in strings
|
||||
assert !('enum' in strings)
|
||||
assert !('final' in strings)
|
||||
assert !('equals' in strings)
|
||||
assert !('new' in strings)
|
||||
assert !('null' in strings)
|
||||
assert !('public' in strings)
|
||||
assert !('super' in strings)
|
||||
assert !('null' in strings)
|
||||
}
|
||||
|
||||
public void testAfterInstanceof() throws Exception {
|
||||
configureByFile("AfterInstanceof.java");
|
||||
assert "A" in myFixture.lookupElementStrings
|
||||
|
||||
+42
@@ -37,6 +37,48 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReturnTypeCompatibility() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTypeArgsConsistency() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testWildcardBounds() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAmbiguity1() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAmbiguityVarargs() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAmbiguityRawGenerics() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testNoInferenceResult() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testInferenceFromArgs() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testInContexts() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCastInContexts() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
|
||||
}
|
||||
|
||||
+6
-5
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.completion.util;
|
||||
|
||||
import com.intellij.codeInsight.completion.InsertionContext;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
|
||||
/**
|
||||
@@ -39,16 +40,16 @@ public class MethodParenthesesHandler extends ParenthesesInsertHandler<LookupEle
|
||||
public static boolean hasParams(LookupElement item, LookupElement[] allItems, final boolean overloadsMatter, final PsiMethod method) {
|
||||
boolean hasParams = method.getParameterList().getParametersCount() > 0;
|
||||
if (overloadsMatter){
|
||||
hasParams |= hasOverloads(item, allItems, method);
|
||||
hasParams |= hasOverloads(allItems, method);
|
||||
}
|
||||
return hasParams;
|
||||
}
|
||||
|
||||
private static boolean hasOverloads(LookupElement item, LookupElement[] allItems, final PsiMethod method) {
|
||||
private static boolean hasOverloads(LookupElement[] allItems, final PsiMethod method) {
|
||||
String name = method.getName();
|
||||
for (LookupElement item1 : allItems) {
|
||||
final Object o = item1.getObject();
|
||||
if (item.getObject() != o && o instanceof PsiMethod && ((PsiMethod)o).getName().equals(name)) {
|
||||
for (LookupElement another : allItems) {
|
||||
final PsiElement element = another.getPsiElement();
|
||||
if (method != element && element instanceof PsiMethod && ((PsiMethod)element).getName().equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import java.util.Map;
|
||||
* Date: 10/7/11
|
||||
*/
|
||||
public class BuildDataManager implements StorageOwner {
|
||||
private static final int VERSION = 7;
|
||||
private static final int VERSION = 8;
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.storage.BuildDataManager");
|
||||
private static final String SRC_TO_OUTPUTS_STORAGE = "src-out";
|
||||
private static final String SRC_TO_FORM_STORAGE = "src-form";
|
||||
|
||||
@@ -780,7 +780,7 @@ public class Mappings {
|
||||
final Util myFuture;
|
||||
final Util myPresent;
|
||||
|
||||
final boolean myPreprocessOnly;
|
||||
final boolean myEasyMode; // true means: no need to search for affected files, only preprocess data for integrate
|
||||
|
||||
private class DelayedWorks {
|
||||
class Triple {
|
||||
@@ -820,7 +820,7 @@ public class Mappings {
|
||||
myQueue.add(new Triple(ownerClass, changedField, future));
|
||||
}
|
||||
|
||||
boolean doWork(final Collection<File> affectedFiles) {
|
||||
boolean doWork(@NotNull final Collection<File> affectedFiles) {
|
||||
if (!myQueue.isEmpty()) {
|
||||
debug("Starting delayed works.");
|
||||
|
||||
@@ -888,7 +888,7 @@ public class Mappings {
|
||||
myFuture = null;
|
||||
myPresent = null;
|
||||
|
||||
myPreprocessOnly = true;
|
||||
myEasyMode = true;
|
||||
|
||||
delta.myIsRebuild = true;
|
||||
}
|
||||
@@ -907,7 +907,7 @@ public class Mappings {
|
||||
|
||||
myFuture = new Util(delta);
|
||||
myPresent = new Util();
|
||||
myPreprocessOnly = true;
|
||||
myEasyMode = true;
|
||||
}
|
||||
|
||||
private Differential(final Mappings delta,
|
||||
@@ -931,22 +931,24 @@ public class Mappings {
|
||||
myFuture = new Util(delta);
|
||||
myPresent = new Util();
|
||||
|
||||
myPreprocessOnly = false;
|
||||
myEasyMode = false;
|
||||
}
|
||||
|
||||
private void processDisappearedClasses() {
|
||||
myDelta.compensateRemovedContent(myFilesToCompile);
|
||||
|
||||
final Collection<String> removed = myDelta.myRemovedFiles;
|
||||
if (!myEasyMode) {
|
||||
final Collection<String> removed = myDelta.myRemovedFiles;
|
||||
|
||||
if (removed != null) {
|
||||
for (final String file : removed) {
|
||||
final Collection<ClassRepr> classes = mySourceFileToClasses.get(myContext.get(file));
|
||||
if (removed != null) {
|
||||
for (final String file : removed) {
|
||||
final Collection<ClassRepr> classes = mySourceFileToClasses.get(myContext.get(file));
|
||||
|
||||
if (classes != null) {
|
||||
for (ClassRepr c : classes) {
|
||||
debug("Affecting usages of removed class ", c.name);
|
||||
affectAll(c.name, myAffectedFiles, myFilter);
|
||||
if (classes != null) {
|
||||
for (ClassRepr c : classes) {
|
||||
debug("Affecting usages of removed class ", c.name);
|
||||
affectAll(c.name, myAffectedFiles, myFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1542,8 +1544,8 @@ public class Mappings {
|
||||
}
|
||||
}
|
||||
|
||||
if (myPreprocessOnly) {
|
||||
return false;
|
||||
if (myEasyMode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
myPresent.appendDependents(it, state.myDependants);
|
||||
@@ -1657,7 +1659,7 @@ public class Mappings {
|
||||
}
|
||||
debug("End of changed classes processing");
|
||||
|
||||
return true;
|
||||
return !myEasyMode;
|
||||
}
|
||||
|
||||
private void processRemovedClases(final DiffState state) {
|
||||
@@ -1671,7 +1673,7 @@ public class Mappings {
|
||||
myDelta.myChangedFiles.add(fileName);
|
||||
}
|
||||
|
||||
if (!myPreprocessOnly) {
|
||||
if (!myEasyMode) {
|
||||
myPresent.appendDependents(c, state.myDependants);
|
||||
debug("Adding usages of class ", c.name);
|
||||
state.myAffectedUsages.add(c.createUsage());
|
||||
@@ -1690,7 +1692,7 @@ public class Mappings {
|
||||
myDelta.registerAddedSuperClass(c.name, sup);
|
||||
}
|
||||
|
||||
if (!myPreprocessOnly) {
|
||||
if (!myEasyMode) {
|
||||
final TIntHashSet depClasses = myClassToClassDependency.get(c.name);
|
||||
|
||||
if (depClasses != null) {
|
||||
@@ -1799,7 +1801,7 @@ public class Mappings {
|
||||
}
|
||||
|
||||
debug("Begin of Differentiate:");
|
||||
debug("Easy mode: ", myPreprocessOnly);
|
||||
debug("Easy mode: ", myEasyMode);
|
||||
|
||||
processDisappearedClasses();
|
||||
|
||||
@@ -1818,34 +1820,34 @@ public class Mappings {
|
||||
final Set<ClassRepr> pastClasses = (Set<ClassRepr>)mySourceFileToClasses.get(fileName);
|
||||
final DiffState state = new DiffState(Difference.make(pastClasses, classes));
|
||||
|
||||
if (!processChangedClasses(state) && !myPreprocessOnly) {
|
||||
// turning non-incremental
|
||||
return false;
|
||||
if (!processChangedClasses(state)) {
|
||||
if (!myEasyMode) {
|
||||
// turning non-incremental
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
processRemovedClases(state);
|
||||
processAddedClasses(state);
|
||||
|
||||
if (!myPreprocessOnly) {
|
||||
if (!myEasyMode) {
|
||||
calculateAffectedFiles(state);
|
||||
}
|
||||
}
|
||||
|
||||
debug("End of Differentiate.");
|
||||
|
||||
if (!myPreprocessOnly) {
|
||||
final Collection<String> removed = myDelta.myRemovedFiles;
|
||||
if (removed != null) {
|
||||
for (final String r : removed) {
|
||||
myAffectedFiles.remove(new File(r));
|
||||
}
|
||||
}
|
||||
|
||||
return myDelayedWorks.doWork(myAffectedFiles);
|
||||
}
|
||||
else {
|
||||
if (myEasyMode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Collection<String> removed = myDelta.myRemovedFiles;
|
||||
if (removed != null) {
|
||||
for (final String r : removed) {
|
||||
myAffectedFiles.remove(new File(r));
|
||||
}
|
||||
}
|
||||
return myDelayedWorks.doWork(myAffectedFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ public class JarHandlerBase {
|
||||
public FileAttributes getAttributes(@NotNull final VirtualFile file) {
|
||||
synchronized (lock) {
|
||||
final JarFile.JarEntry entry = convertToEntry(file);
|
||||
return entry != null ? new FileAttributes(entry.isDirectory(), false, false, entry.getSize(), entry.getTime(), false) : null;
|
||||
return entry != null ? new FileAttributes(entry.isDirectory(), false, false, false, entry.getSize(), entry.getTime(), false) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
package com.intellij.codeInsight.lookup;
|
||||
|
||||
import com.intellij.codeInsight.completion.InsertionContext;
|
||||
import com.intellij.navigation.PsiElementNavigationItem;
|
||||
import com.intellij.openapi.util.ClassConditionKey;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.ResolveResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -47,6 +49,21 @@ public abstract class LookupElement extends UserDataHolderBase {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement getPsiElement() {
|
||||
Object o = getObject();
|
||||
if (o instanceof PsiElement) {
|
||||
return (PsiElement)o;
|
||||
}
|
||||
if (o instanceof ResolveResult) {
|
||||
return ((ResolveResult)o).getElement();
|
||||
}
|
||||
if (o instanceof PsiElementNavigationItem) {
|
||||
return ((PsiElementNavigationItem)o).getTargetElement();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
final Object object = getObject();
|
||||
if (object instanceof PsiElement) {
|
||||
|
||||
+5
@@ -652,6 +652,11 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
|
||||
|
||||
hideAutopopupIfMeaningless();
|
||||
|
||||
CompletionPhase oldPhase = CompletionServiceImpl.getCompletionPhase();
|
||||
if (oldPhase instanceof CompletionPhase.CommittingDocuments) {
|
||||
((CompletionPhase.CommittingDocuments)oldPhase).replaced = true;
|
||||
}
|
||||
|
||||
final CompletionPhase.CommittingDocuments phase = new CompletionPhase.CommittingDocuments(this, myEditor);
|
||||
CompletionServiceImpl.setCompletionPhase(phase);
|
||||
|
||||
|
||||
@@ -1,275 +1,266 @@
|
||||
/*
|
||||
* 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.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupItem;
|
||||
import com.intellij.codeInsight.lookup.LookupValueWithPsiElement;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.navigation.PsiElementNavigationItem;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.ResolveResult;
|
||||
import com.intellij.psi.filters.TrueFilter;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.patterns.PlatformPatterns.character;
|
||||
|
||||
public class CompletionUtil {
|
||||
static final Key<OffsetTranslator> RANGE_TRANSLATION = Key.create("completion.rangeTranslation");
|
||||
public static final Key<TailType> TAIL_TYPE_ATTR = LookupItem.TAIL_TYPE_ATTR;
|
||||
|
||||
private static final CompletionData ourGenericCompletionData = new CompletionData() {
|
||||
{
|
||||
final CompletionVariant variant = new CompletionVariant(PsiElement.class, TrueFilter.INSTANCE);
|
||||
variant.addCompletionFilter(TrueFilter.INSTANCE, TailType.NONE);
|
||||
registerVariant(variant);
|
||||
}
|
||||
};
|
||||
private static final HashMap<FileType, NotNullLazyValue<CompletionData>> ourCustomCompletionDatas = new HashMap<FileType, NotNullLazyValue<CompletionData>>();
|
||||
|
||||
public static final @NonNls String DUMMY_IDENTIFIER = CompletionInitializationContext.DUMMY_IDENTIFIER;
|
||||
public static final @NonNls String DUMMY_IDENTIFIER_TRIMMED = DUMMY_IDENTIFIER.trim();
|
||||
|
||||
public static boolean startsWith(String text, String prefix) {
|
||||
//if (text.length() <= prefix.length()) return false;
|
||||
return toLowerCase(text).startsWith(toLowerCase(prefix));
|
||||
}
|
||||
|
||||
private static String toLowerCase(String text) {
|
||||
CodeInsightSettings settings = CodeInsightSettings.getInstance();
|
||||
switch (settings.COMPLETION_CASE_SENSITIVE) {
|
||||
case CodeInsightSettings.NONE:
|
||||
return text.toLowerCase();
|
||||
|
||||
case CodeInsightSettings.FIRST_LETTER: {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(text.toLowerCase());
|
||||
if (buffer.length() > 0) {
|
||||
buffer.setCharAt(0, text.charAt(0));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
default:
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CompletionData getCompletionDataByElement(@Nullable final PsiElement position, @NotNull PsiFile originalFile) {
|
||||
if (position == null) return null;
|
||||
|
||||
final FileType fileType = position.getParent().getLanguage().getAssociatedFileType();
|
||||
if (fileType != null) {
|
||||
final CompletionData mainData = getCompletionDataByFileType(fileType);
|
||||
if (mainData != null) {
|
||||
return mainData;
|
||||
}
|
||||
}
|
||||
|
||||
final CompletionData mainData = getCompletionDataByFileType(originalFile.getFileType());
|
||||
return mainData != null ? mainData : ourGenericCompletionData;
|
||||
}
|
||||
|
||||
/** @see CompletionDataEP */
|
||||
@Deprecated
|
||||
public static void registerCompletionData(FileType fileType, NotNullLazyValue<CompletionData> completionData) {
|
||||
ourCustomCompletionDatas.put(fileType, completionData);
|
||||
}
|
||||
|
||||
/** @see CompletionDataEP */
|
||||
@Deprecated
|
||||
public static void registerCompletionData(FileType fileType, final CompletionData completionData) {
|
||||
registerCompletionData(fileType, new NotNullLazyValue<CompletionData>() {
|
||||
@NotNull
|
||||
protected CompletionData compute() {
|
||||
return completionData;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CompletionData getCompletionDataByFileType(FileType fileType) {
|
||||
for(CompletionDataEP ep: Extensions.getExtensions(CompletionDataEP.EP_NAME)) {
|
||||
if (ep.fileType.equals(fileType.getName())) {
|
||||
return ep.getHandler();
|
||||
}
|
||||
}
|
||||
final NotNullLazyValue<CompletionData> lazyValue = ourCustomCompletionDatas.get(fileType);
|
||||
return lazyValue == null ? null : lazyValue.getValue();
|
||||
}
|
||||
|
||||
|
||||
public static boolean shouldShowFeature(final CompletionParameters parameters, @NonNls final String id) {
|
||||
if (FeatureUsageTracker.getInstance().isToBeAdvertisedInLookup(id, parameters.getPosition().getProject())) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureShown(id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String findJavaIdentifierPrefix(CompletionParameters parameters) {
|
||||
return findJavaIdentifierPrefix(parameters.getPosition(), parameters.getOffset());
|
||||
}
|
||||
|
||||
public static String findJavaIdentifierPrefix(final PsiElement insertedElement, final int offset) {
|
||||
return findIdentifierPrefix(insertedElement, offset, character().javaIdentifierPart(), character().javaIdentifierStart());
|
||||
}
|
||||
|
||||
public static String findReferenceOrAlphanumericPrefix(CompletionParameters parameters) {
|
||||
String prefix = findReferencePrefix(parameters);
|
||||
return prefix == null ? findAlphanumericPrefix(parameters) : prefix;
|
||||
}
|
||||
|
||||
public static String findAlphanumericPrefix(CompletionParameters parameters) {
|
||||
return findIdentifierPrefix(parameters.getPosition().getContainingFile(), parameters.getOffset(), character().letterOrDigit(), character().letterOrDigit());
|
||||
}
|
||||
|
||||
public static String findIdentifierPrefix(PsiElement insertedElement, int offset, ElementPattern<Character> idPart,
|
||||
ElementPattern<Character> idStart) {
|
||||
if(insertedElement == null) return "";
|
||||
final String text = insertedElement.getText();
|
||||
|
||||
final int offsetInElement = offset - insertedElement.getTextRange().getStartOffset();
|
||||
int start = offsetInElement - 1;
|
||||
while (start >=0 ) {
|
||||
if (!idPart.accepts(text.charAt(start))) break;
|
||||
--start;
|
||||
}
|
||||
while (start + 1 < offsetInElement && !idStart.accepts(text.charAt(start + 1))) {
|
||||
start++;
|
||||
}
|
||||
|
||||
return text.substring(start + 1, offsetInElement).trim();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String findReferencePrefix(CompletionParameters parameters) {
|
||||
return CompletionData.getReferencePrefix(parameters.getPosition(), parameters.getOffset());
|
||||
}
|
||||
|
||||
|
||||
static InsertionContext emulateInsertion(InsertionContext oldContext, int newStart, final LookupElement item) {
|
||||
final InsertionContext newContext = newContext(oldContext, item);
|
||||
emulateInsertion(item, newStart, newContext);
|
||||
return newContext;
|
||||
}
|
||||
|
||||
private static InsertionContext newContext(InsertionContext oldContext, LookupElement forElement) {
|
||||
final Editor editor = oldContext.getEditor();
|
||||
return new InsertionContext(new OffsetMap(editor.getDocument()), Lookup.AUTO_INSERT_SELECT_CHAR, new LookupElement[]{forElement}, oldContext.getFile(), editor,
|
||||
oldContext.shouldAddCompletionChar());
|
||||
}
|
||||
|
||||
public static InsertionContext newContext(InsertionContext oldContext, LookupElement forElement, int startOffset, int tailOffset) {
|
||||
final InsertionContext context = newContext(oldContext, forElement);
|
||||
setOffsets(context, startOffset, tailOffset);
|
||||
return context;
|
||||
}
|
||||
|
||||
public static void emulateInsertion(LookupElement item, int offset, InsertionContext context) {
|
||||
setOffsets(context, offset, offset);
|
||||
|
||||
final Editor editor = context.getEditor();
|
||||
final Document document = editor.getDocument();
|
||||
final String lookupString = item.getLookupString();
|
||||
|
||||
document.insertString(offset, lookupString);
|
||||
editor.getCaretModel().moveToOffset(context.getTailOffset());
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document);
|
||||
item.handleInsert(context);
|
||||
}
|
||||
|
||||
private static void setOffsets(InsertionContext context, int offset, final int tailOffset) {
|
||||
final OffsetMap offsetMap = context.getOffsetMap();
|
||||
offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, offset);
|
||||
offsetMap.addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, tailOffset);
|
||||
offsetMap.addOffset(CompletionInitializationContext.SELECTION_END_OFFSET, tailOffset);
|
||||
context.setTailOffset(tailOffset);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement getTargetElement(LookupElement lookupElement) {
|
||||
Object object = lookupElement.getObject();
|
||||
if (object instanceof ResolveResult) {
|
||||
object = ((ResolveResult)object).getElement();
|
||||
}
|
||||
|
||||
if (object instanceof PsiElement) {
|
||||
return getOriginalElement((PsiElement)object);
|
||||
}
|
||||
|
||||
if (object instanceof PsiElementNavigationItem) {
|
||||
return ((PsiElementNavigationItem)object).getTargetElement();
|
||||
}
|
||||
|
||||
if (object instanceof LookupValueWithPsiElement) {
|
||||
final PsiElement element = ((LookupValueWithPsiElement)object).getElement();
|
||||
if (element != null) return getOriginalElement(element);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T extends PsiElement> T getOriginalElement(@NotNull T psi) {
|
||||
final PsiFile file = psi.getContainingFile();
|
||||
if (file != null && file != file.getOriginalFile() && psi.getTextRange() != null) {
|
||||
TextRange range = psi.getTextRange();
|
||||
Integer start = range.getStartOffset();
|
||||
Integer end = range.getEndOffset();
|
||||
final Document document = file.getViewProvider().getDocument();
|
||||
if (document != null) {
|
||||
final OffsetTranslator translator = document.getUserData(RANGE_TRANSLATION);
|
||||
if (translator != null) {
|
||||
start = translator.translateOffset(start);
|
||||
end = translator.translateOffset(end);
|
||||
if (start == null || end == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (T)PsiTreeUtil.findElementOfClassAtRange(file.getOriginalFile(), start, end, psi.getClass());
|
||||
}
|
||||
|
||||
return psi;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T extends PsiElement> T getOriginalOrSelf(@NotNull T psi) {
|
||||
final T element = getOriginalElement(psi);
|
||||
return element == null ? psi : element;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupItem;
|
||||
import com.intellij.codeInsight.lookup.LookupValueWithPsiElement;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.filters.TrueFilter;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.patterns.PlatformPatterns.character;
|
||||
|
||||
public class CompletionUtil {
|
||||
static final Key<OffsetTranslator> RANGE_TRANSLATION = Key.create("completion.rangeTranslation");
|
||||
public static final Key<TailType> TAIL_TYPE_ATTR = LookupItem.TAIL_TYPE_ATTR;
|
||||
|
||||
private static final CompletionData ourGenericCompletionData = new CompletionData() {
|
||||
{
|
||||
final CompletionVariant variant = new CompletionVariant(PsiElement.class, TrueFilter.INSTANCE);
|
||||
variant.addCompletionFilter(TrueFilter.INSTANCE, TailType.NONE);
|
||||
registerVariant(variant);
|
||||
}
|
||||
};
|
||||
private static final HashMap<FileType, NotNullLazyValue<CompletionData>> ourCustomCompletionDatas = new HashMap<FileType, NotNullLazyValue<CompletionData>>();
|
||||
|
||||
public static final @NonNls String DUMMY_IDENTIFIER = CompletionInitializationContext.DUMMY_IDENTIFIER;
|
||||
public static final @NonNls String DUMMY_IDENTIFIER_TRIMMED = DUMMY_IDENTIFIER.trim();
|
||||
|
||||
public static boolean startsWith(String text, String prefix) {
|
||||
//if (text.length() <= prefix.length()) return false;
|
||||
return toLowerCase(text).startsWith(toLowerCase(prefix));
|
||||
}
|
||||
|
||||
private static String toLowerCase(String text) {
|
||||
CodeInsightSettings settings = CodeInsightSettings.getInstance();
|
||||
switch (settings.COMPLETION_CASE_SENSITIVE) {
|
||||
case CodeInsightSettings.NONE:
|
||||
return text.toLowerCase();
|
||||
|
||||
case CodeInsightSettings.FIRST_LETTER: {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(text.toLowerCase());
|
||||
if (buffer.length() > 0) {
|
||||
buffer.setCharAt(0, text.charAt(0));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
default:
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CompletionData getCompletionDataByElement(@Nullable final PsiElement position, @NotNull PsiFile originalFile) {
|
||||
if (position == null) return null;
|
||||
|
||||
final FileType fileType = position.getParent().getLanguage().getAssociatedFileType();
|
||||
if (fileType != null) {
|
||||
final CompletionData mainData = getCompletionDataByFileType(fileType);
|
||||
if (mainData != null) {
|
||||
return mainData;
|
||||
}
|
||||
}
|
||||
|
||||
final CompletionData mainData = getCompletionDataByFileType(originalFile.getFileType());
|
||||
return mainData != null ? mainData : ourGenericCompletionData;
|
||||
}
|
||||
|
||||
/** @see CompletionDataEP */
|
||||
@Deprecated
|
||||
public static void registerCompletionData(FileType fileType, NotNullLazyValue<CompletionData> completionData) {
|
||||
ourCustomCompletionDatas.put(fileType, completionData);
|
||||
}
|
||||
|
||||
/** @see CompletionDataEP */
|
||||
@Deprecated
|
||||
public static void registerCompletionData(FileType fileType, final CompletionData completionData) {
|
||||
registerCompletionData(fileType, new NotNullLazyValue<CompletionData>() {
|
||||
@NotNull
|
||||
protected CompletionData compute() {
|
||||
return completionData;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CompletionData getCompletionDataByFileType(FileType fileType) {
|
||||
for(CompletionDataEP ep: Extensions.getExtensions(CompletionDataEP.EP_NAME)) {
|
||||
if (ep.fileType.equals(fileType.getName())) {
|
||||
return ep.getHandler();
|
||||
}
|
||||
}
|
||||
final NotNullLazyValue<CompletionData> lazyValue = ourCustomCompletionDatas.get(fileType);
|
||||
return lazyValue == null ? null : lazyValue.getValue();
|
||||
}
|
||||
|
||||
|
||||
public static boolean shouldShowFeature(final CompletionParameters parameters, @NonNls final String id) {
|
||||
if (FeatureUsageTracker.getInstance().isToBeAdvertisedInLookup(id, parameters.getPosition().getProject())) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureShown(id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String findJavaIdentifierPrefix(CompletionParameters parameters) {
|
||||
return findJavaIdentifierPrefix(parameters.getPosition(), parameters.getOffset());
|
||||
}
|
||||
|
||||
public static String findJavaIdentifierPrefix(final PsiElement insertedElement, final int offset) {
|
||||
return findIdentifierPrefix(insertedElement, offset, character().javaIdentifierPart(), character().javaIdentifierStart());
|
||||
}
|
||||
|
||||
public static String findReferenceOrAlphanumericPrefix(CompletionParameters parameters) {
|
||||
String prefix = findReferencePrefix(parameters);
|
||||
return prefix == null ? findAlphanumericPrefix(parameters) : prefix;
|
||||
}
|
||||
|
||||
public static String findAlphanumericPrefix(CompletionParameters parameters) {
|
||||
return findIdentifierPrefix(parameters.getPosition().getContainingFile(), parameters.getOffset(), character().letterOrDigit(), character().letterOrDigit());
|
||||
}
|
||||
|
||||
public static String findIdentifierPrefix(PsiElement insertedElement, int offset, ElementPattern<Character> idPart,
|
||||
ElementPattern<Character> idStart) {
|
||||
if(insertedElement == null) return "";
|
||||
final String text = insertedElement.getText();
|
||||
|
||||
final int offsetInElement = offset - insertedElement.getTextRange().getStartOffset();
|
||||
int start = offsetInElement - 1;
|
||||
while (start >=0 ) {
|
||||
if (!idPart.accepts(text.charAt(start))) break;
|
||||
--start;
|
||||
}
|
||||
while (start + 1 < offsetInElement && !idStart.accepts(text.charAt(start + 1))) {
|
||||
start++;
|
||||
}
|
||||
|
||||
return text.substring(start + 1, offsetInElement).trim();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String findReferencePrefix(CompletionParameters parameters) {
|
||||
return CompletionData.getReferencePrefix(parameters.getPosition(), parameters.getOffset());
|
||||
}
|
||||
|
||||
|
||||
static InsertionContext emulateInsertion(InsertionContext oldContext, int newStart, final LookupElement item) {
|
||||
final InsertionContext newContext = newContext(oldContext, item);
|
||||
emulateInsertion(item, newStart, newContext);
|
||||
return newContext;
|
||||
}
|
||||
|
||||
private static InsertionContext newContext(InsertionContext oldContext, LookupElement forElement) {
|
||||
final Editor editor = oldContext.getEditor();
|
||||
return new InsertionContext(new OffsetMap(editor.getDocument()), Lookup.AUTO_INSERT_SELECT_CHAR, new LookupElement[]{forElement}, oldContext.getFile(), editor,
|
||||
oldContext.shouldAddCompletionChar());
|
||||
}
|
||||
|
||||
public static InsertionContext newContext(InsertionContext oldContext, LookupElement forElement, int startOffset, int tailOffset) {
|
||||
final InsertionContext context = newContext(oldContext, forElement);
|
||||
setOffsets(context, startOffset, tailOffset);
|
||||
return context;
|
||||
}
|
||||
|
||||
public static void emulateInsertion(LookupElement item, int offset, InsertionContext context) {
|
||||
setOffsets(context, offset, offset);
|
||||
|
||||
final Editor editor = context.getEditor();
|
||||
final Document document = editor.getDocument();
|
||||
final String lookupString = item.getLookupString();
|
||||
|
||||
document.insertString(offset, lookupString);
|
||||
editor.getCaretModel().moveToOffset(context.getTailOffset());
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document);
|
||||
item.handleInsert(context);
|
||||
}
|
||||
|
||||
private static void setOffsets(InsertionContext context, int offset, final int tailOffset) {
|
||||
final OffsetMap offsetMap = context.getOffsetMap();
|
||||
offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, offset);
|
||||
offsetMap.addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, tailOffset);
|
||||
offsetMap.addOffset(CompletionInitializationContext.SELECTION_END_OFFSET, tailOffset);
|
||||
context.setTailOffset(tailOffset);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement getTargetElement(LookupElement lookupElement) {
|
||||
PsiElement psiElement = lookupElement.getPsiElement();
|
||||
if (psiElement != null) {
|
||||
return getOriginalElement(psiElement);
|
||||
}
|
||||
|
||||
Object object = lookupElement.getObject();
|
||||
if (object instanceof LookupValueWithPsiElement) {
|
||||
final PsiElement element = ((LookupValueWithPsiElement)object).getElement();
|
||||
if (element != null) return getOriginalElement(element);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T extends PsiElement> T getOriginalElement(@NotNull T psi) {
|
||||
final PsiFile file = psi.getContainingFile();
|
||||
if (file != null && file != file.getOriginalFile() && psi.getTextRange() != null) {
|
||||
TextRange range = psi.getTextRange();
|
||||
Integer start = range.getStartOffset();
|
||||
Integer end = range.getEndOffset();
|
||||
final Document document = file.getViewProvider().getDocument();
|
||||
if (document != null) {
|
||||
final OffsetTranslator translator = document.getUserData(RANGE_TRANSLATION);
|
||||
if (translator != null) {
|
||||
start = translator.translateOffset(start);
|
||||
end = translator.translateOffset(end);
|
||||
if (start == null || end == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (T)PsiTreeUtil.findElementOfClassAtRange(file.getOriginalFile(), start, end, psi.getClass());
|
||||
}
|
||||
|
||||
return psi;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T extends PsiElement> T getOriginalOrSelf(@NotNull T psi) {
|
||||
final T element = getOriginalElement(psi);
|
||||
return element == null ? psi : element;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -31,8 +31,7 @@ public class LookupElementProximityWeigher extends CompletionWeigher {
|
||||
return PsiProximityComparator.getProximity(new NullableComputable<PsiElement>() {
|
||||
@Override
|
||||
public PsiElement compute() {
|
||||
Object object = item.getObject();
|
||||
return object instanceof PsiElement ? (PsiElement)object : null;
|
||||
return item.getPsiElement();
|
||||
}
|
||||
}, location.getCompletionParameters().getPosition(), location.getProcessingContext());
|
||||
}
|
||||
|
||||
+3
-8
@@ -73,14 +73,9 @@ public class DefaultLookupItemRenderer extends LookupElementRenderer<LookupItem>
|
||||
return ((Iconable)o).getIcon(Iconable.ICON_FLAG_VISIBILITY);
|
||||
}
|
||||
|
||||
if (o instanceof LookupValueWithPsiElement) {
|
||||
o = ((LookupValueWithPsiElement)o).getElement();
|
||||
}
|
||||
if (o instanceof PsiElement) {
|
||||
final PsiElement element = (PsiElement)o;
|
||||
if (element.isValid()) {
|
||||
return element.getIcon(Iconable.ICON_FLAG_VISIBILITY);
|
||||
}
|
||||
final PsiElement element = item.getPsiElement();
|
||||
if (element != null && element.isValid()) {
|
||||
return element.getIcon(Iconable.ICON_FLAG_VISIBILITY);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+2
-5
@@ -44,10 +44,7 @@ import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.tree.CompositeElement;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import com.intellij.ui.AutoScrollFromSourceHandler;
|
||||
import com.intellij.ui.AutoScrollToSourceHandler;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.ui.TreeSpeedSearch;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.ui.treeStructure.actions.CollapseAllAction;
|
||||
import com.intellij.ui.treeStructure.actions.ExpandAllAction;
|
||||
@@ -132,7 +129,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
};
|
||||
|
||||
final DefaultTreeModel model = new DefaultTreeModel(new DefaultMutableTreeNode(treeStructure.getRootElement()));
|
||||
myTree = new Tree(model);
|
||||
myTree = new JBTreeWithHintProvider(model);
|
||||
myTree.setRootVisible(showRootNode);
|
||||
myTree.setShowsRootHandles(true);
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.openapi.diff;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
@@ -25,6 +27,7 @@ public interface DiffViewer {
|
||||
|
||||
JComponent getComponent();
|
||||
|
||||
@Nullable
|
||||
JComponent getPreferredFocusedComponent();
|
||||
|
||||
int getContentsNumber();
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.openapi.fileChooser.FileChooser;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileElement;
|
||||
import com.intellij.openapi.fileChooser.PathChooserDialog;
|
||||
import com.intellij.openapi.fileChooser.impl.FileChooserUtil;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.fileEditor.ex.FileEditorProviderManager;
|
||||
@@ -96,7 +97,7 @@ public class OpenFileAction extends AnAction implements DumbAware {
|
||||
@NotNull final List<VirtualFile> result) {
|
||||
for (final VirtualFile file : result) {
|
||||
if (file.isDirectory()) {
|
||||
ProjectUtil.openOrImport(file.getPath(), project, false);
|
||||
FileChooserUtil.setLastOpenedFile(ProjectUtil.openOrImport(file.getPath(), project, false), file);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ public class OpenFileAction extends AnAction implements DumbAware {
|
||||
IdeBundle.message("title.open.project"),
|
||||
Messages.getQuestionIcon());
|
||||
if (answer == 0) {
|
||||
ProjectUtil.openOrImport(file.getPath(), project, false);
|
||||
FileChooserUtil.setLastOpenedFile(ProjectUtil.openOrImport(file.getPath(), project, false), file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.openapi.diff.impl.external.DiscloseMultiRequest;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.ui.content.Content;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -121,6 +122,7 @@ public class CompositeDiffPanel implements DiffViewer {
|
||||
return myUi.getComponent();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
final Content[] contents = myUi.getContents();
|
||||
|
||||
@@ -77,7 +77,6 @@ import java.util.List;
|
||||
|
||||
public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSidesContainer {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.DiffPanelImpl");
|
||||
public static final int DIFF_DIVIDER_POLYGONS_OFFSET = 3;
|
||||
|
||||
private final DiffSplitterI mySplitter;
|
||||
private final DiffPanelOuterComponent myPanel;
|
||||
@@ -111,7 +110,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid
|
||||
private CanNotCalculateDiffPanel myNotCalculateDiffPanel;
|
||||
private final VisibleAreaListener myVisibleAreaListener;
|
||||
|
||||
public DiffPanelImpl(final Window owner, Project project, boolean enableToolbar, boolean horizontal) {
|
||||
public DiffPanelImpl(final Window owner, Project project, boolean enableToolbar, boolean horizontal, int diffDividerPolygonsOffset) {
|
||||
myProject = project;
|
||||
myIsHorizontal = horizontal;
|
||||
myOptions = new DiffPanelOptions(this);
|
||||
@@ -130,7 +129,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid
|
||||
|
||||
if (horizontal) {
|
||||
mySplitter = new DiffSplitter(myLeftSide.getComponent(), myRightSide.getComponent(),
|
||||
new DiffDividerPaint(this, FragmentSide.SIDE1, DIFF_DIVIDER_POLYGONS_OFFSET), myData);
|
||||
new DiffDividerPaint(this, FragmentSide.SIDE1, diffDividerPolygonsOffset), myData);
|
||||
}
|
||||
else {
|
||||
mySplitter = new HorizontalDiffSplitter(myLeftSide.getComponent(), myRightSide.getComponent());
|
||||
@@ -335,7 +334,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid
|
||||
}
|
||||
|
||||
int[] getFragmentBeginnings(FragmentSide side) {
|
||||
return getLineBlocks().getBegginings(side);
|
||||
return getLineBlocks().getBeginnings(side);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
@@ -369,6 +368,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid
|
||||
return getLineBlocks().getCount() > 0 || myNotCalculateDiffPanel != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myCurrentSide.getFocusableComponent();
|
||||
}
|
||||
|
||||
@@ -18,8 +18,10 @@ package com.intellij.openapi.diff.impl;
|
||||
import com.intellij.openapi.diff.impl.highlighting.FragmentSide;
|
||||
import com.intellij.openapi.diff.impl.splitter.LineBlocks;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface EditingSides {
|
||||
@Nullable
|
||||
Editor getEditor(FragmentSide side);
|
||||
LineBlocks getLineBlocks();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.diff.DiffViewer;
|
||||
import com.intellij.openapi.diff.DiffViewerType;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -46,6 +47,7 @@ public class EmptyDiffViewer implements DiffViewer {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return null;
|
||||
|
||||
+2
-1
@@ -38,6 +38,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class DiffManagerImpl extends DiffManager implements JDOMExternalizable {
|
||||
public static final int FULL_DIFF_DIVIDER_POLYGONS_OFFSET = 3;
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.external.DiffManagerImpl");
|
||||
|
||||
private static final Externalizer<String> TOOL_PATH_UPDATE = new Externalizer<String>() {
|
||||
@@ -137,7 +138,7 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable {
|
||||
}
|
||||
|
||||
public DiffPanel createDiffPanel(Window window, Project project) {
|
||||
return new DiffPanelImpl(window, project, true, true);
|
||||
return new DiffPanelImpl(window, project, true, true, FULL_DIFF_DIVIDER_POLYGONS_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
-1
@@ -22,17 +22,22 @@ import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.diff.DiffBundle;
|
||||
import com.intellij.openapi.diff.impl.incrementalMerge.Change;
|
||||
import com.intellij.openapi.diff.impl.incrementalMerge.MergeList;
|
||||
import com.intellij.openapi.diff.impl.util.DiffPanelOuterComponent;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FilteringIterator;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class ApplyNonConflicts extends AnAction implements DumbAware {
|
||||
public ApplyNonConflicts() {
|
||||
@Nullable private final DiffPanelOuterComponent myDiffPanel;
|
||||
|
||||
public ApplyNonConflicts(@Nullable DiffPanelOuterComponent diffPanel) {
|
||||
super(DiffBundle.message("merge.dialog.apply.all.non.conflicting.changes.action.name"), null, AllIcons.Diff.ApplyNotConflicts);
|
||||
myDiffPanel = diffPanel;
|
||||
}
|
||||
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
@@ -41,6 +46,9 @@ public class ApplyNonConflicts extends AnAction implements DumbAware {
|
||||
for (Change change : notConflicts) {
|
||||
Change.apply(change, MergeList.BRANCH_SIDE);
|
||||
}
|
||||
if (myDiffPanel != null) {
|
||||
myDiffPanel.requestScrollEditors();
|
||||
}
|
||||
}
|
||||
|
||||
public void update(AnActionEvent e) {
|
||||
|
||||
+1
-1
@@ -237,7 +237,7 @@ public class EditorPlace extends JComponent implements Disposable, EditorEx.Repa
|
||||
return myEditor;
|
||||
}
|
||||
|
||||
public void setDocument(Document document) {
|
||||
public void setDocument(@Nullable Document document) {
|
||||
if (document == getDocument()) return;
|
||||
removeEditor();
|
||||
myState.setDocument(document);
|
||||
|
||||
+18
-21
@@ -145,7 +145,7 @@ public class MergePanel2 implements DiffViewer {
|
||||
toolbar.addAction(new OpenPartialDiffAction(1, 2, AllIcons.Diff.RightDiff));
|
||||
toolbar.addAction(new OpenPartialDiffAction(0, 2, AllIcons.Diff.BranchDiff));
|
||||
toolbar.addSeparator();
|
||||
toolbar.addAction(new ApplyNonConflicts());
|
||||
toolbar.addAction(new ApplyNonConflicts(myPanel));
|
||||
toolbar.addSeparator();
|
||||
toolbar.addAction(new MergeToolSettingsAction(getEditors()));
|
||||
}
|
||||
@@ -177,6 +177,7 @@ public class MergePanel2 implements DiffViewer {
|
||||
/**
|
||||
* @deprecated Because it references by index.
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public Editor getEditor(int index) {
|
||||
return getEditorPlace(index).getEditor();
|
||||
@@ -265,20 +266,9 @@ public class MergePanel2 implements DiffViewer {
|
||||
}
|
||||
Editor editor = place.getEditor();
|
||||
DiffEditorState editorState = place.getState();
|
||||
((EditorEx)editor).setHighlighter(EditorHighlighterFactory.getInstance().
|
||||
createEditorHighlighter(editorState.getFileType(), settings, editorState.getProject()));
|
||||
}
|
||||
|
||||
public void setAdditionalLinesAndColumns(int lines, int columns) {
|
||||
for (Editor editor : getEditors()) {
|
||||
editor.getSettings().setAdditionalLinesCount(lines);
|
||||
editor.getSettings().setAdditionalColumnsCount(columns);
|
||||
}
|
||||
}
|
||||
|
||||
public void setShowLineNumbers(boolean show) {
|
||||
for (Editor editor : getEditors()) {
|
||||
MergeToolEditorSetting.LINE_NUMBERS.apply(editor, show);
|
||||
if (editor != null) {
|
||||
((EditorEx)editor).setHighlighter(EditorHighlighterFactory.getInstance().
|
||||
createEditorHighlighter(editorState.getFileType(), settings, editorState.getProject()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,6 +329,7 @@ public class MergePanel2 implements DiffViewer {
|
||||
parent.setTitle(windowTitle);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JDialog getDialogWrapperParent() {
|
||||
Component panel = myPanel;
|
||||
while (panel != null){
|
||||
@@ -352,6 +343,7 @@ public class MergePanel2 implements DiffViewer {
|
||||
return myPanel;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return getEditorPlace(1).getContentComponent();
|
||||
}
|
||||
@@ -372,6 +364,7 @@ public class MergePanel2 implements DiffViewer {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MergeRequestImpl getMergeRequest() {
|
||||
return (MergeRequestImpl)(myData instanceof MergeRequestImpl ? myData : null);
|
||||
}
|
||||
@@ -383,6 +376,7 @@ public class MergePanel2 implements DiffViewer {
|
||||
mySide = side;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Editor getEditor(FragmentSide side) {
|
||||
return MergePanel2.this.getEditor(mySide.getIndex() + side.getIndex());
|
||||
}
|
||||
@@ -399,8 +393,8 @@ public class MergePanel2 implements DiffViewer {
|
||||
if (centerComponent.isShowing()) {
|
||||
centerComponent.requestFocus();
|
||||
}
|
||||
int[] toLeft = getPrimaryBegginings(myDividers[0].getPaint());
|
||||
int[] toRight = getPrimaryBegginings(myDividers[1].getPaint());
|
||||
int[] toLeft = getPrimaryBeginnings(myDividers[0].getPaint());
|
||||
int[] toRight = getPrimaryBeginnings(myDividers[1].getPaint());
|
||||
int line;
|
||||
if (toLeft.length > 0 && toRight.length > 0) {
|
||||
line = Math.min(toLeft[0], toRight[0]);
|
||||
@@ -417,10 +411,10 @@ public class MergePanel2 implements DiffViewer {
|
||||
SyncScrollSupport.scrollEditor(centerEditor, line);
|
||||
}
|
||||
|
||||
private int[] getPrimaryBegginings(DiffDividerPaint paint) {
|
||||
private int[] getPrimaryBeginnings(DiffDividerPaint paint) {
|
||||
FragmentSide primarySide = paint.getLeftSide();
|
||||
LOG.assertTrue(getEditor(1) == paint.getSides().getEditor(primarySide));
|
||||
return paint.getSides().getLineBlocks().getBegginings(primarySide);
|
||||
return paint.getSides().getLineBlocks().getBeginnings(primarySide, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,6 +460,7 @@ public class MergePanel2 implements DiffViewer {
|
||||
return getContentType();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Project getProject() {
|
||||
return myData == null ? null : myData.getProject();
|
||||
}
|
||||
@@ -512,12 +507,13 @@ public class MergePanel2 implements DiffViewer {
|
||||
mySide = side;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Editor getEditor() {
|
||||
return MergePanel2.this.getEditor(mySide.getMergeIndex());
|
||||
}
|
||||
|
||||
public int[] getFragmentStartingLines() {
|
||||
return myMergeList.getChanges(mySide).getLineBlocks().getBegginings(MergeList.BRANCH_SIDE);
|
||||
return myMergeList.getChanges(mySide).getLineBlocks().getBeginnings(MergeList.BRANCH_SIDE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,7 +527,7 @@ public class MergePanel2 implements DiffViewer {
|
||||
if (myMergeList != null) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
FragmentSide branchSide = FragmentSide.fromIndex(i);
|
||||
beginnings.addAll(myMergeList.getChanges(branchSide).getLineBlocks().getBegginings(MergeList.BASE_SIDE));
|
||||
beginnings.addAll(myMergeList.getChanges(branchSide).getLineBlocks().getBeginnings(MergeList.BASE_SIDE));
|
||||
}
|
||||
}
|
||||
int[] result = beginnings.toArray();
|
||||
@@ -540,6 +536,7 @@ public class MergePanel2 implements DiffViewer {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static MergePanel2 fromDataContext(DataContext dataContext) {
|
||||
DiffViewer diffComponent = PlatformDataKeys.DIFF_VIEWER.getData(dataContext);
|
||||
return diffComponent instanceof MergePanel2 ? (MergePanel2)diffComponent : null;
|
||||
|
||||
+71
-54
@@ -22,20 +22,18 @@ import com.intellij.openapi.diff.impl.highlighting.FragmentSide;
|
||||
import com.intellij.openapi.diff.impl.incrementalMerge.Change;
|
||||
import com.intellij.openapi.diff.impl.incrementalMerge.ChangeList;
|
||||
import com.intellij.openapi.diff.impl.util.TextDiffType;
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class LineBlocks {
|
||||
public static final LineBlocks EMPTY = new LineBlocks(SimpleIntervalProvider.EMPTY, new TextDiffType[0]);
|
||||
public static final LineBlocks EMPTY = new LineBlocks(Collections.<Diff>emptyList());
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.splitter.LineBlocks");
|
||||
private final IntervalsProvider myIntervalsProvider;
|
||||
private final TextDiffType[] myTypes;
|
||||
private final List<Diff> myDiffs;
|
||||
|
||||
private LineBlocks(IntervalsProvider intervalsProvider, TextDiffType[] types) {
|
||||
myIntervalsProvider = intervalsProvider;
|
||||
myTypes = types;
|
||||
private LineBlocks(List<Diff> diffs) {
|
||||
myDiffs = diffs;
|
||||
}
|
||||
|
||||
public Interval getVisibleIndices(Trapezium visibleArea) {
|
||||
@@ -56,23 +54,40 @@ public class LineBlocks {
|
||||
}
|
||||
|
||||
public TextDiffType getType(int index) {
|
||||
return myTypes[index];
|
||||
return myDiffs.get(index).getDiffType();
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return getBegginings(FragmentSide.SIDE1).length;
|
||||
return getBeginnings(FragmentSide.SIDE1).length;
|
||||
}
|
||||
|
||||
public int[] getBegginings(FragmentSide side) {
|
||||
IntArrayList result = new IntArrayList(getIntervals(side).length);
|
||||
/**
|
||||
* Get beginnings of all the changes from the specified side.
|
||||
* @param side Side of the changes.
|
||||
*/
|
||||
public int[] getBeginnings(FragmentSide side) {
|
||||
return getBeginnings(side, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get beginnings of the changes from the specified side.
|
||||
* @param side Side of the changes.
|
||||
* @param unappliedOnly If true - only unapplied changes will be considered, if false - all changes (both applied and not applied).
|
||||
*/
|
||||
public int[] getBeginnings(FragmentSide side, boolean unappliedOnly) {
|
||||
List<Integer> result = new ArrayList<Integer>(myDiffs.size());
|
||||
int previousBeginning = Integer.MIN_VALUE;
|
||||
Interval[] sideIntervals = getIntervals(side);
|
||||
for (Interval sideInterval : sideIntervals) {
|
||||
int start = sideInterval.getStart();
|
||||
if (start != previousBeginning) result.add(start);
|
||||
previousBeginning = start;
|
||||
|
||||
for (Diff diff : myDiffs) {
|
||||
if (!unappliedOnly || !diff.getDiffType().isApplied()) {
|
||||
Interval interval = diff.getInterval(side);
|
||||
int start = interval.getStart();
|
||||
if (start != previousBeginning) result.add(start);
|
||||
previousBeginning = start;
|
||||
}
|
||||
}
|
||||
return result.toArray();
|
||||
|
||||
return ArrayUtil.toIntArray(result);
|
||||
}
|
||||
|
||||
static int getMaxStartedIndex(Interval[] intervals, int start) {
|
||||
@@ -99,7 +114,19 @@ public class LineBlocks {
|
||||
}
|
||||
|
||||
public Interval[] getIntervals(FragmentSide side) {
|
||||
return myIntervalsProvider.getIntervals(side);
|
||||
Interval[] intervals = new Interval[myDiffs.size()];
|
||||
for (int i = 0; i < intervals.length; i++) {
|
||||
intervals[i] = myDiffs.get(i).getInterval(side);
|
||||
}
|
||||
return intervals;
|
||||
}
|
||||
|
||||
public TextDiffType[] getTypes() {
|
||||
TextDiffType[] types = new TextDiffType[myDiffs.size()];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
types[i] = myDiffs.get(i).getDiffType();
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
private int transform(int location, Interval[] domain, Interval[] range) {
|
||||
@@ -147,20 +174,13 @@ public class LineBlocks {
|
||||
|
||||
static LineBlocks createLineBlocks(LineBlock[] blocks) {
|
||||
Arrays.sort(blocks, LineBlock.COMPARATOR);
|
||||
Interval[] intervals1 = new Interval[blocks.length];
|
||||
Interval[] intervals2 = new Interval[blocks.length];
|
||||
TextDiffType[] types = new TextDiffType[blocks.length];
|
||||
for (int i = 0; i < blocks.length; i++) {
|
||||
LineBlock block = blocks[i];
|
||||
intervals1[i] = new Interval(block.getStartingLine1(), block.getModifiedLines1());
|
||||
intervals2[i] = new Interval(block.getStartingLine2(), block.getModifiedLines2());
|
||||
types[i] = TextDiffType.create(block.getType());
|
||||
List<Diff> diffs = new ArrayList<Diff>(blocks.length);
|
||||
for (LineBlock block : blocks) {
|
||||
Interval interval1 = new Interval(block.getStartingLine1(), block.getModifiedLines1());
|
||||
Interval interval2 = new Interval(block.getStartingLine2(), block.getModifiedLines2());
|
||||
diffs.add(new Diff(interval1, interval2, TextDiffType.create(block.getType())));
|
||||
}
|
||||
return create(intervals1, intervals2, types);
|
||||
}
|
||||
|
||||
private static LineBlocks create(Interval[] intervals1, Interval[] intervals2, TextDiffType[] types) {
|
||||
return new LineBlocks(new SimpleIntervalProvider(intervals1, intervals2), types);
|
||||
return new LineBlocks(diffs);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -168,44 +188,41 @@ public class LineBlocks {
|
||||
// changes may come mixed, need to sort them to get correct intervals
|
||||
Collections.sort(changes, ChangeList.CHANGE_ORDER);
|
||||
|
||||
ArrayList<Interval> intervals1 = new ArrayList<Interval>();
|
||||
ArrayList<Interval> intervals2 = new ArrayList<Interval>();
|
||||
ArrayList<TextDiffType> types = new ArrayList<TextDiffType>();
|
||||
List<Diff> diffs = new ArrayList<Diff>(changes.size());
|
||||
for (Change change : changes) {
|
||||
if (!change.isValid()) { continue; }
|
||||
int start1 = change.getChangeSide(FragmentSide.SIDE1).getStartLine();
|
||||
int end1 = change.getChangeSide(FragmentSide.SIDE1).getEndLine();
|
||||
intervals1.add(Interval.fromTo(start1, end1));
|
||||
Interval interval1 = Interval.fromTo(start1, end1);
|
||||
|
||||
int start2 = change.getChangeSide(FragmentSide.SIDE2).getStartLine();
|
||||
int end2 = change.getChangeSide(FragmentSide.SIDE2).getEndLine();
|
||||
intervals2.add(Interval.fromTo(start2, end2));
|
||||
Interval interval2 = Interval.fromTo(start2, end2);
|
||||
|
||||
types.add(change.getType().getTypeKey());
|
||||
diffs.add(new Diff(interval1, interval2, change.getType().getTypeKey()));
|
||||
}
|
||||
return create(intervals1.toArray(new Interval[intervals1.size()]),
|
||||
intervals2.toArray(new Interval[intervals2.size()]), types.toArray(new TextDiffType[types.size()]));
|
||||
return new LineBlocks(diffs);
|
||||
}
|
||||
|
||||
public TextDiffType[] getTypes() {
|
||||
return myTypes;
|
||||
}
|
||||
private static class Diff {
|
||||
|
||||
public interface IntervalsProvider {
|
||||
Interval[] getIntervals(FragmentSide side);
|
||||
}
|
||||
|
||||
public static class SimpleIntervalProvider implements IntervalsProvider {
|
||||
private final Interval[][] myIntervals = new Interval[2][];
|
||||
public static final IntervalsProvider EMPTY = new SimpleIntervalProvider(new Interval[0], new Interval[0]);
|
||||
@NotNull private final Interval myIntervalForSide1;
|
||||
@NotNull private final Interval myIntervalForSide2;
|
||||
@NotNull private final TextDiffType myDiffType;
|
||||
|
||||
public SimpleIntervalProvider(Interval[] intervals1, Interval[] intervals2) {
|
||||
myIntervals[0] = intervals1;
|
||||
myIntervals[1] = intervals2;
|
||||
private Diff(@NotNull Interval intervalForSide1, @NotNull Interval intervalForSide2, @NotNull TextDiffType type) {
|
||||
myIntervalForSide1 = intervalForSide1;
|
||||
myIntervalForSide2 = intervalForSide2;
|
||||
myDiffType = type;
|
||||
}
|
||||
|
||||
public Interval[] getIntervals(FragmentSide side) {
|
||||
return myIntervals[side.getIndex()];
|
||||
@NotNull
|
||||
public TextDiffType getDiffType() {
|
||||
return myDiffType;
|
||||
}
|
||||
|
||||
public Interval getInterval(FragmentSide side) {
|
||||
return side == FragmentSide.SIDE1 ? myIntervalForSide1 : myIntervalForSide2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,13 @@ package com.intellij.openapi.diff.impl.util;
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface FocusDiffSide {
|
||||
DataKey<FocusDiffSide> DATA_KEY = DataKey.create("focusedDiffSide");
|
||||
@Deprecated String FOCUSED_DIFF_SIDE = DATA_KEY.getName();
|
||||
|
||||
@Nullable
|
||||
Editor getEditor();
|
||||
|
||||
int[] getFragmentStartingLines();
|
||||
|
||||
@@ -382,6 +382,6 @@ public class TempFileSystem extends NewVirtualFileSystem {
|
||||
final FSItem item = convert(file);
|
||||
if (item == null) return null;
|
||||
final long length = item instanceof FSFile ? ((FSFile)item).myContent.length : 0;
|
||||
return new FileAttributes(item.isDirectory(), false, false, length, item.myTimestamp, item.myWritable);
|
||||
return new FileAttributes(item.isDirectory(), false, false, false, length, item.myTimestamp, item.myWritable);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -20,7 +20,6 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileAttributes;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.impl.local.LocalFileSystemBase;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -222,9 +221,10 @@ public class Win32LocalFileSystem extends LocalFileSystemBase {
|
||||
if (fileInfo == null) return null;
|
||||
|
||||
final boolean isDirectory = isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_DIRECTORY);
|
||||
final boolean isSymlink = isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_REPARSE_POINT);
|
||||
final boolean isSpecial = isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_DEVICE);
|
||||
final boolean isSymlink = isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_REPARSE_POINT);
|
||||
final boolean isHidden = isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_HIDDEN);
|
||||
final boolean isWritable = !isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_READONLY);
|
||||
return new FileAttributes(isDirectory, isSymlink, isSpecial, fileInfo.length, fileInfo.timestamp, isWritable);
|
||||
return new FileAttributes(isDirectory, isSpecial, isSymlink, isHidden, fileInfo.length, fileInfo.timestamp, isWritable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ public class FileWatcherTest extends PlatformLangTestCase {
|
||||
try {
|
||||
myConnection.disconnect();
|
||||
myWatcher.shutdown();
|
||||
assertFalse(myWatcher.isOperational());
|
||||
}
|
||||
finally {
|
||||
myFileSystem = null;
|
||||
|
||||
+2
-29
@@ -15,13 +15,10 @@
|
||||
*/
|
||||
package com.intellij.openapi.vfs.local;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -30,6 +27,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static com.intellij.openapi.util.io.IoTestUtil.createTempLink;
|
||||
|
||||
public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
private LocalFileSystem myFileSystem;
|
||||
|
||||
@@ -265,32 +264,6 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
assertEquals(vSubChild, vSubChildRel);
|
||||
}
|
||||
|
||||
// todo[r.sh] use NIO2 API after migration to JDK 7
|
||||
public static File createTempLink(final String target, final String link) throws InterruptedException, ExecutionException {
|
||||
final boolean isAbsolute = SystemInfo.isUnix && StringUtil.startsWithChar(link, '/') ||
|
||||
SystemInfo.isWindows && link.matches("^[c-zC-Z]:[/\\\\].*$");
|
||||
final File linkFile = isAbsolute ? new File(link) : new File(FileUtil.getTempDirectory(), link);
|
||||
assertTrue(link, !linkFile.exists() || linkFile.delete());
|
||||
final File parentDir = linkFile.getParentFile();
|
||||
assertTrue("link=" + link + ", parent=" + parentDir, parentDir != null && (parentDir.isDirectory() || parentDir.mkdirs()));
|
||||
|
||||
final GeneralCommandLine commandLine;
|
||||
if (SystemInfo.isWindows) {
|
||||
commandLine = new File(target).isDirectory()
|
||||
? new GeneralCommandLine("cmd", "/C", "mklink", "/D", linkFile.getAbsolutePath(), target)
|
||||
: new GeneralCommandLine("cmd", "/C", "mklink", linkFile.getAbsolutePath(), target);
|
||||
}
|
||||
else {
|
||||
commandLine = new GeneralCommandLine("ln", "-s", target, linkFile.getAbsolutePath());
|
||||
}
|
||||
final int res = commandLine.createProcess().waitFor();
|
||||
assertEquals(commandLine.getCommandLineString(), 0, res);
|
||||
|
||||
final File targetFile = new File(target);
|
||||
assertEquals("target=" + target + ", link=" + linkFile, targetFile.exists(), linkFile.exists());
|
||||
return linkFile;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VirtualFile refreshAndFind(final File ioFile) {
|
||||
refresh();
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.openapi.editor.highlighter.EditorHighlighter;
|
||||
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import junit.framework.Assert;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -35,6 +36,10 @@ import java.util.List;
|
||||
* Time: 21:00:49
|
||||
*/
|
||||
public class EditorTestUtil {
|
||||
public static final String CARET_TAG = "<caret>";
|
||||
public static final String SELECTION_START_TAG = "<selection>";
|
||||
public static final String SELECTION_END_TAG = "</selection>";
|
||||
|
||||
public static final char BACKSPACE_FAKE_CHAR = '\uFFFF';
|
||||
public static final char SMART_ENTER_FAKE_CHAR = '\uFFFE';
|
||||
|
||||
@@ -83,4 +88,33 @@ public class EditorTestUtil {
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public static int getCaretPosition(@NotNull final String content) {
|
||||
return getCaretAndSelectionPosition(content)[0];
|
||||
}
|
||||
|
||||
public static int[] getCaretAndSelectionPosition(@NotNull final String content) {
|
||||
int caretPosInSourceFile = content.indexOf(CARET_TAG);
|
||||
int selectionStartInSourceFile = content.indexOf(SELECTION_START_TAG);
|
||||
int selectionEndInSourceFile = content.indexOf(SELECTION_END_TAG);
|
||||
if (selectionStartInSourceFile >= 0) {
|
||||
if (caretPosInSourceFile >= 0) {
|
||||
if (caretPosInSourceFile < selectionStartInSourceFile) {
|
||||
selectionStartInSourceFile -= CARET_TAG.length();
|
||||
selectionEndInSourceFile -= CARET_TAG.length();
|
||||
}
|
||||
else {
|
||||
if (caretPosInSourceFile < selectionEndInSourceFile) {
|
||||
caretPosInSourceFile -= SELECTION_START_TAG.length();
|
||||
}
|
||||
else {
|
||||
caretPosInSourceFile -= SELECTION_START_TAG.length() + SELECTION_END_TAG.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
selectionEndInSourceFile -= SELECTION_START_TAG.length();
|
||||
}
|
||||
|
||||
return new int[]{caretPosInSourceFile, selectionStartInSourceFile, selectionEndInSourceFile};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,8 @@ public abstract class LexerTestCase extends UsefulTestCase {
|
||||
String fileName = PathManager.getHomePath() + "/" + getDirPath() + "/" + getTestName(true) + "." + fileExt;
|
||||
String text = "";
|
||||
try {
|
||||
text = StringUtil.convertLineSeparators(FileUtil.loadFile(new File(fileName)).trim());
|
||||
String fileText = FileUtil.loadFile(new File(fileName));
|
||||
text = StringUtil.convertLineSeparators(shouldTrim() ? fileText.trim() : fileText);
|
||||
}
|
||||
catch (IOException e) {
|
||||
fail("can't load file " + fileName + ": " + e.getMessage());
|
||||
@@ -101,6 +102,10 @@ public abstract class LexerTestCase extends UsefulTestCase {
|
||||
doTest(text);
|
||||
}
|
||||
|
||||
protected boolean shouldTrim() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String getTokenText(Lexer lexer) {
|
||||
String text = lexer.getBufferSequence().subSequence(lexer.getTokenStart(), lexer.getTokenEnd()).toString();
|
||||
text = StringUtil.replace(text, "\n", "\\n");
|
||||
|
||||
+15
-9
@@ -26,6 +26,7 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.testFramework.UsefulTestCase;
|
||||
import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -77,15 +78,20 @@ public abstract class LightPlatformCodeInsightFixtureTestCase extends UsefulTest
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return absolute path to the test data.
|
||||
*
|
||||
* @return absolute path to the test data.
|
||||
*/
|
||||
@NonNls
|
||||
protected String getTestDataPath() {
|
||||
return PathManager.getHomePath().replace(File.separatorChar, '/') + getBasePath();
|
||||
}
|
||||
/**
|
||||
* Return absolute path to the test data. Not intended to be overridden.
|
||||
*
|
||||
* @return absolute path to the test data.
|
||||
*/
|
||||
@NonNls
|
||||
protected String getTestDataPath() {
|
||||
String path = isCommunity() ? PlatformTestUtil.getCommunityPath() : PathManager.getHomePath();
|
||||
return path.replace(File.separatorChar, '/') + getBasePath();
|
||||
}
|
||||
|
||||
protected boolean isCommunity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
|
||||
@@ -58,7 +58,7 @@ public class LineBlock {
|
||||
return myStartingLine2 + myModifiedLines2;
|
||||
}
|
||||
|
||||
public static final Comparator COMPARATOR = new Comparator<LineBlock>() {
|
||||
public static final Comparator<LineBlock> COMPARATOR = new Comparator<LineBlock>() {
|
||||
public int compare(LineBlock block1, LineBlock block2) {
|
||||
return block1.getStartingLine1() - block2.getStartingLine1();
|
||||
}
|
||||
|
||||
@@ -18,12 +18,23 @@ package com.intellij.openapi.util.io;
|
||||
import com.intellij.util.StringBuilderSpinAllocator;
|
||||
import org.intellij.lang.annotations.MagicConstant;
|
||||
|
||||
import static com.intellij.util.BitUtil.isSet;
|
||||
import static com.intellij.util.BitUtil.notSet;
|
||||
|
||||
/**
|
||||
* @version 11.1
|
||||
* @see FileSystemUtil#getAttributes(String)
|
||||
*/
|
||||
@SuppressWarnings("OctalInteger")
|
||||
public final class FileAttributes {
|
||||
public static final int DIRECTORY = 0x0001;
|
||||
public static final int SPECIAL = 0x0002;
|
||||
public static final int SYM_LINK = 0x0010;
|
||||
public static final int HIDDEN = 0x0100;
|
||||
|
||||
@MagicConstant(flags = {DIRECTORY, SPECIAL, SYM_LINK, HIDDEN})
|
||||
public @interface FileType { }
|
||||
|
||||
public static final int OWNER_READ = 0400;
|
||||
public static final int OWNER_WRITE = 0200;
|
||||
public static final int OWNER_EXECUTE = 0100;
|
||||
@@ -34,52 +45,99 @@ public final class FileAttributes {
|
||||
public static final int OTHERS_WRITE = 0002;
|
||||
public static final int OTHERS_EXECUTE = 0001;
|
||||
|
||||
@MagicConstant(flags = {
|
||||
OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, OTHERS_READ, OTHERS_WRITE, OTHERS_EXECUTE
|
||||
})
|
||||
@MagicConstant(flags = {OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, OTHERS_READ, OTHERS_WRITE, OTHERS_EXECUTE})
|
||||
public @interface Permissions { }
|
||||
|
||||
public final boolean isFile;
|
||||
public final boolean isDirectory;
|
||||
public final boolean isSymlink;
|
||||
public final boolean isSpecial;
|
||||
|
||||
/** In bytes, 0 for symlinks and special files. */
|
||||
/**
|
||||
* {@linkplain #DIRECTORY} and {@linkplain #SPECIAL} bits are mutually exclusive, none of them set means a regular file.<br/>
|
||||
* {@linkplain #SYM_LINK} bit may be set along with above ones (which then denote a type of a link target).<br/>
|
||||
* {@linkplain #HIDDEN} bit may be only set on Windows.
|
||||
*/
|
||||
@FileType
|
||||
public final int type;
|
||||
|
||||
/**
|
||||
* In bytes, 0 for special files.<br/>
|
||||
* For symlinks - length of a link target.
|
||||
*/
|
||||
public final long length;
|
||||
|
||||
/** In milliseconds (note that actual resolution may be less accurate). */
|
||||
/**
|
||||
* In milliseconds (actual resolution depends on a file system and may be less accurate).<br/>
|
||||
* For symlinks - timestamp of a link target.
|
||||
*/
|
||||
public final long lastModified;
|
||||
|
||||
/** UNIX permission bits (for Windows only OWNER_WRITE matters and OWNER_READ/EXECUTE are always set), or -1 if not supported. */
|
||||
/**
|
||||
* UNIX permission bits (for Windows only OWNER_WRITE matters and OWNER_READ/EXECUTE are always set), or -1 if not supported.<br/>
|
||||
* For symlinks - permissions of a link target.
|
||||
*/
|
||||
@Permissions
|
||||
public final int permissions;
|
||||
|
||||
// todo: hidden flag (?)
|
||||
|
||||
public FileAttributes(final boolean isDirectory,
|
||||
final boolean isSymlink,
|
||||
final boolean isSpecial,
|
||||
final boolean isSymlink,
|
||||
final boolean isHidden,
|
||||
final long length,
|
||||
final long lastModified,
|
||||
final boolean writable) {
|
||||
this(isDirectory, isSymlink, isSpecial, length, lastModified, OWNER_READ | OWNER_EXECUTE | (writable ? OWNER_WRITE : 0));
|
||||
final boolean isWritable) {
|
||||
this(type(isDirectory, isSpecial, isSymlink, isHidden), length, lastModified, OWNER_READ | OWNER_EXECUTE | (isWritable ? OWNER_WRITE : 0));
|
||||
}
|
||||
|
||||
public FileAttributes(final boolean isDirectory,
|
||||
final boolean isSymlink,
|
||||
final boolean isSpecial,
|
||||
final boolean isSymlink,
|
||||
final long length,
|
||||
final long lastModified,
|
||||
@Permissions final int permissions) {
|
||||
this.isFile = !isDirectory && !isSymlink && !isSpecial;
|
||||
this.isDirectory = isDirectory;
|
||||
this.isSymlink = isSymlink;
|
||||
this.isSpecial = isSpecial;
|
||||
this.length = isSymlink || isSpecial ? 0 : length;
|
||||
this(type(isDirectory, isSpecial, isSymlink, false), length, lastModified, permissions);
|
||||
}
|
||||
|
||||
private FileAttributes(@FileType final int type,
|
||||
final long length,
|
||||
final long lastModified,
|
||||
@Permissions final int permissions) {
|
||||
if (isSet(type, DIRECTORY) && isSet(type, SPECIAL)) {
|
||||
throw new IllegalArgumentException("DIRECTORY and SPECIAL bits cannot be set simultaneously");
|
||||
}
|
||||
|
||||
this.type = type;
|
||||
this.length = length;
|
||||
this.lastModified = lastModified;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
@FileType
|
||||
private static int type(final boolean isDirectory, final boolean isSpecial, final boolean isSymlink, final boolean isHidden) {
|
||||
@FileType int type = 0;
|
||||
if (isDirectory) type |= DIRECTORY;
|
||||
if (isSpecial) type |= SPECIAL;
|
||||
if (isSymlink) type |= SYM_LINK;
|
||||
if (isHidden) type |= HIDDEN;
|
||||
return type;
|
||||
}
|
||||
|
||||
/** Is {@code true} for files and symlinks to files (see {@linkplain #isRegularFile()}). */
|
||||
public boolean isFile() {
|
||||
return notSet(type, DIRECTORY | SPECIAL);
|
||||
}
|
||||
|
||||
/** Is {@code true} for pure regular files only (see {@linkplain #isFile()}). */
|
||||
public boolean isRegularFile() {
|
||||
return notSet(type, DIRECTORY | SPECIAL | SYM_LINK);
|
||||
}
|
||||
|
||||
public boolean isSymLink() {
|
||||
return isSet(type, SYM_LINK);
|
||||
}
|
||||
|
||||
public boolean isWritable() {
|
||||
return permissions == -1 || isSet(permissions, OWNER_WRITE) || isSet(permissions, GROUP_WRITE) || isSet(permissions, OTHERS_WRITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -87,10 +145,7 @@ public final class FileAttributes {
|
||||
|
||||
final FileAttributes that = (FileAttributes)o;
|
||||
|
||||
if (isDirectory != that.isDirectory) return false;
|
||||
if (isFile != that.isFile) return false;
|
||||
if (isSpecial != that.isSpecial) return false;
|
||||
if (isSymlink != that.isSymlink) return false;
|
||||
if (type != that.type) return false;
|
||||
if (lastModified != that.lastModified) return false;
|
||||
if (permissions != that.permissions) return false;
|
||||
if (length != that.length) return false;
|
||||
@@ -100,10 +155,7 @@ public final class FileAttributes {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (isFile ? 1 : 0);
|
||||
result = 31 * result + (isDirectory ? 1 : 0);
|
||||
result = 31 * result + (isSymlink ? 1 : 0);
|
||||
result = 31 * result + (isSpecial ? 1 : 0);
|
||||
int result = type;
|
||||
result = 31 * result + (int)(length ^ (length >>> 32));
|
||||
result = 31 * result + (int)(lastModified ^ (lastModified >>> 32));
|
||||
result = 31 * result + permissions;
|
||||
@@ -115,10 +167,10 @@ public final class FileAttributes {
|
||||
final StringBuilder sb = StringBuilderSpinAllocator.alloc();
|
||||
try {
|
||||
sb.append("[type:");
|
||||
if (isFile) sb.append('f');
|
||||
if (isDirectory) sb.append('d');
|
||||
if (isSymlink) sb.append('l');
|
||||
if (isSpecial) sb.append('!');
|
||||
if (isSet(type, DIRECTORY)) sb.append('d');
|
||||
else if (isSet(type, SPECIAL)) sb.append('!');
|
||||
else sb.append('f');
|
||||
if (isSet(type, SYM_LINK)) sb.append('l');
|
||||
|
||||
sb.append(" length:").append(length);
|
||||
|
||||
|
||||
@@ -18,12 +18,14 @@ package com.intellij.openapi.util.io;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Memory;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Pointer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
@@ -31,47 +33,73 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.util.BitUtil.isSet;
|
||||
import static com.intellij.util.BitUtil.notSet;
|
||||
|
||||
/**
|
||||
* @version 11.1
|
||||
*/
|
||||
public class FileSystemUtil {
|
||||
public static final String FORCE_USE_NIO2_KEY = "idea.io.use.nio2";
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.FileSystemUtil");
|
||||
|
||||
private interface Mediator {
|
||||
@Nullable
|
||||
FileAttributes getAttributes(@NotNull String path) throws Exception;
|
||||
|
||||
@Nullable
|
||||
String resolveSymLink(@NotNull String path) throws Exception;
|
||||
|
||||
void setPermissions(@NotNull String path, int permissions) throws Exception;
|
||||
|
||||
@NotNull
|
||||
String getName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static final Mediator ourMediator;
|
||||
static {
|
||||
Mediator mediator = null;
|
||||
private static Mediator ourMediator = getMediator();
|
||||
|
||||
// todo: move IdeaWin32 interface to this package, add mediator
|
||||
private static Mediator getMediator() {
|
||||
final boolean forceUseNio2 = SystemProperties.getBooleanProperty(FORCE_USE_NIO2_KEY, false);
|
||||
final String quickTestPath = SystemInfo.isWindows ? "C:\\" : "/";
|
||||
|
||||
if (SystemInfo.isLinux || SystemInfo.isMac || SystemInfo.isSolaris || SystemInfo.isFreeBSD) {
|
||||
if (!forceUseNio2) {
|
||||
if (SystemInfo.isLinux || SystemInfo.isMac || SystemInfo.isSolaris || SystemInfo.isFreeBSD) {
|
||||
try {
|
||||
final Mediator mediator = new JnaUnixMediatorImpl();
|
||||
mediator.getAttributes(quickTestPath);
|
||||
return mediator;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
LOG.warn(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SystemInfo.isJavaVersionAtLeast("1.7") && !"1.7.0-ea".equals(SystemInfo.JAVA_VERSION)) {
|
||||
try {
|
||||
mediator = new JnaUnixMediatorImpl();
|
||||
mediator.getAttributes("/"); // quick test
|
||||
final Mediator mediator = new Nio2MediatorImpl();
|
||||
mediator.getAttributes(quickTestPath);
|
||||
return mediator;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
LOG.error(t);
|
||||
mediator = null;
|
||||
LOG.warn(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (mediator == null && SystemInfo.isJavaVersionAtLeast("1.7") && !"1.7.0-ea".equals(SystemInfo.JAVA_VERSION)) {
|
||||
try {
|
||||
mediator = new Jdk7MediatorImpl();
|
||||
mediator.getAttributes("/"); // quick test
|
||||
}
|
||||
catch (Throwable t) {
|
||||
LOG.error(t);
|
||||
mediator = null;
|
||||
}
|
||||
}
|
||||
// todo: after introducing IdeaWin32 mediator, fail tests at this point, or issue a warning in production
|
||||
return new StandardMediatorImpl();
|
||||
}
|
||||
|
||||
if (mediator == null) {
|
||||
// todo: after introducing IdeaWin32 mediator, fail tests at this point, or issue a warning in production
|
||||
mediator = new StandardMediatorImpl();
|
||||
}
|
||||
@TestOnly
|
||||
static void resetMediator() {
|
||||
ourMediator = getMediator();
|
||||
}
|
||||
|
||||
ourMediator = mediator;
|
||||
@TestOnly
|
||||
static String getMediatorName() {
|
||||
return ourMediator.getName();
|
||||
}
|
||||
|
||||
private FileSystemUtil() { }
|
||||
@@ -87,14 +115,21 @@ public class FileSystemUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Nullable
|
||||
public static FileAttributes getAttributes(@NotNull final File file) {
|
||||
return getAttributes(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
public static boolean isSymLink(@NotNull final String path) {
|
||||
if (SystemInfo.areSymLinksSupported) {
|
||||
final FileAttributes attributes = getAttributes(path);
|
||||
return attributes != null && attributes.isSymlink;
|
||||
return attributes != null && attributes.isSymLink();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public static boolean isSymLink(@NotNull final File file) {
|
||||
return isSymLink(file.getAbsolutePath());
|
||||
}
|
||||
@@ -113,6 +148,7 @@ public class FileSystemUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Nullable
|
||||
public static String resolveSymLink(@NotNull final File file) {
|
||||
return resolveSymLink(file.getAbsolutePath());
|
||||
@@ -123,6 +159,7 @@ public class FileSystemUtil {
|
||||
return attributes != null ? attributes.permissions : -1;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public static int getPermissions(@NotNull final File file) {
|
||||
return getPermissions(file.getAbsolutePath());
|
||||
}
|
||||
@@ -142,19 +179,10 @@ public class FileSystemUtil {
|
||||
setPermissions(file.getAbsolutePath(), permissions);
|
||||
}
|
||||
|
||||
private interface Mediator {
|
||||
@Nullable
|
||||
FileAttributes getAttributes(@NotNull String path) throws Exception;
|
||||
|
||||
@Nullable
|
||||
String resolveSymLink(@NotNull String path) throws Exception;
|
||||
|
||||
void setPermissions(@NotNull String path, int permissions) throws Exception;
|
||||
}
|
||||
|
||||
// todo[r.sh] remove reflection after migration to JDK 7
|
||||
@SuppressWarnings("OctalInteger")
|
||||
private static class Jdk7MediatorImpl implements Mediator {
|
||||
private static class Nio2MediatorImpl implements Mediator {
|
||||
private final Object myDefaultFileSystem;
|
||||
private final Method myGetPath;
|
||||
private final Method myIsSymbolicLink;
|
||||
@@ -163,8 +191,9 @@ public class FileSystemUtil {
|
||||
private final Method myReadAttributes;
|
||||
private final Method mySetAttribute;
|
||||
private final Method myToMillis;
|
||||
private final String mySchema;
|
||||
|
||||
private Jdk7MediatorImpl() throws Exception {
|
||||
private Nio2MediatorImpl() throws Exception {
|
||||
myDefaultFileSystem = Class.forName("java.nio.file.FileSystems").getMethod("getDefault").invoke(null);
|
||||
|
||||
myGetPath = Class.forName("java.nio.file.FileSystem").getMethod("getPath", String.class, String[].class);
|
||||
@@ -189,29 +218,33 @@ public class FileSystemUtil {
|
||||
final Class<?> fileTimeClass = Class.forName("java.nio.file.attribute.FileTime");
|
||||
myToMillis = fileTimeClass.getMethod("toMillis");
|
||||
myToMillis.setAccessible(true);
|
||||
|
||||
mySchema = SystemInfo.isWindows ? "dos:*" : "posix:*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileAttributes getAttributes(@NotNull final String path) throws Exception {
|
||||
try {
|
||||
final Object pathObj = myGetPath.invoke(myDefaultFileSystem, path, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
|
||||
Map attributes = (Map)myReadAttributes.invoke(null, pathObj, mySchema, myNoFollowLinkOptions);
|
||||
final Boolean isSymbolicLink = (Boolean)attributes.get("isSymbolicLink");
|
||||
if (isSymbolicLink) {
|
||||
attributes = (Map)myReadAttributes.invoke(null, pathObj, mySchema, myLinkOptions);
|
||||
}
|
||||
|
||||
final boolean isDirectory = (Boolean)attributes.get("isDirectory");
|
||||
final boolean isOther = (Boolean)attributes.get("isOther");
|
||||
final long size = (Long)attributes.get("size");
|
||||
final long lastModified = (Long)myToMillis.invoke(attributes.get("lastModifiedTime"));
|
||||
if (SystemInfo.isWindows) {
|
||||
final Map attributes = (Map)myReadAttributes.invoke(null, pathObj, "dos:*", myNoFollowLinkOptions);
|
||||
return new FileAttributes((Boolean)attributes.get("isDirectory"),
|
||||
(Boolean)attributes.get("isSymbolicLink"),
|
||||
(Boolean)attributes.get("isOther"),
|
||||
(Long)attributes.get("size"),
|
||||
(Long)myToMillis.invoke(attributes.get("lastModifiedTime")),
|
||||
!(Boolean)attributes.get("readonly"));
|
||||
final boolean isHidden = (Boolean)attributes.get("hidden");
|
||||
final boolean isWritable = !(Boolean)attributes.get("readonly");
|
||||
return new FileAttributes(isDirectory, isOther, isSymbolicLink, isHidden, size, lastModified, isWritable);
|
||||
}
|
||||
else {
|
||||
final Map attributes = (Map)myReadAttributes.invoke(null, pathObj, "posix:*", myNoFollowLinkOptions);
|
||||
return new FileAttributes((Boolean)attributes.get("isDirectory"),
|
||||
(Boolean)attributes.get("isSymbolicLink"),
|
||||
(Boolean)attributes.get("isOther"),
|
||||
(Long)attributes.get("size"),
|
||||
(Long)myToMillis.invoke(attributes.get("lastModifiedTime")),
|
||||
decodePermissions(attributes.get("permissions")));
|
||||
final int permissions = decodePermissions(attributes.get("permissions"));
|
||||
return new FileAttributes(isDirectory, isOther, isSymbolicLink, size, lastModified, permissions);
|
||||
}
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
@@ -243,6 +276,12 @@ public class FileSystemUtil {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "NIO2";
|
||||
}
|
||||
|
||||
private static final Map<String, Integer> ATTRIBUTES_MAP;
|
||||
static {
|
||||
ATTRIBUTES_MAP = new HashMap<String, Integer>();
|
||||
@@ -290,6 +329,7 @@ public class FileSystemUtil {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// thanks to SVNKit for the idea
|
||||
private static class JnaUnixMediatorImpl implements Mediator {
|
||||
@SuppressWarnings("OctalInteger")
|
||||
@@ -302,7 +342,9 @@ public class FileSystemUtil {
|
||||
int PERM_MASK = 0777;
|
||||
|
||||
int lstat(String path, Pointer stat);
|
||||
int stat(String path, Pointer stat);
|
||||
int __lxstat64(int ver, String path, Pointer stat);
|
||||
int __xstat64(int ver, String path, Pointer stat);
|
||||
int chmod(String path, int mode);
|
||||
}
|
||||
|
||||
@@ -333,20 +375,26 @@ public class FileSystemUtil {
|
||||
@Override
|
||||
public synchronized FileAttributes getAttributes(@NotNull final String path) throws Exception {
|
||||
mySharedMem.clear();
|
||||
final int res = SystemInfo.isLinux ? myLibC.__lxstat64(0, path, mySharedMem) : myLibC.lstat(path, mySharedMem);
|
||||
if (res == 0) {
|
||||
final int mode = (SystemInfo.isLinux ? mySharedMem.getInt(myModeOffset) : mySharedMem.getShort(myModeOffset)) & LibC.S_MASK;
|
||||
final boolean isDirectory = (mode & LibC.S_IFDIR) == LibC.S_IFDIR;
|
||||
final boolean isSymlink = (mode & LibC.S_IFLNK) == LibC.S_IFLNK;
|
||||
final boolean isSpecial = !isDirectory && !isSymlink && (mode & LibC.S_IFREG) == 0;
|
||||
final long size = mySharedMem.getLong(mySizeOffset);
|
||||
final long mTime1 = SystemInfo.is32Bit ? mySharedMem.getInt(myTimeOffset) : mySharedMem.getLong(myTimeOffset);
|
||||
final long mTime2 = SystemInfo.is32Bit ? mySharedMem.getInt(myTimeOffset + 4) : mySharedMem.getLong(myTimeOffset + 8);
|
||||
final long mTime = mTime1 * 1000 + mTime2 / 1000000;
|
||||
@FileAttributes.Permissions final int permissions = mode & LibC.PERM_MASK;
|
||||
return new FileAttributes(isDirectory, isSymlink, isSpecial, size, mTime, permissions);
|
||||
int res = SystemInfo.isLinux ? myLibC.__lxstat64(0, path, mySharedMem) : myLibC.lstat(path, mySharedMem);
|
||||
if (res != 0) return null;
|
||||
|
||||
int mode = (SystemInfo.isLinux ? mySharedMem.getInt(myModeOffset) : mySharedMem.getShort(myModeOffset)) & LibC.S_MASK;
|
||||
final boolean isSymlink = (mode & LibC.S_IFLNK) == LibC.S_IFLNK;
|
||||
if (isSymlink) {
|
||||
mySharedMem.clear();
|
||||
res = SystemInfo.isLinux ? myLibC.__xstat64(0, path, mySharedMem) : myLibC.stat(path, mySharedMem);
|
||||
if (res != 0) return null;
|
||||
mode = (SystemInfo.isLinux ? mySharedMem.getInt(myModeOffset) : mySharedMem.getShort(myModeOffset)) & LibC.S_MASK;
|
||||
}
|
||||
return null;
|
||||
|
||||
final boolean isDirectory = (mode & LibC.S_IFDIR) == LibC.S_IFDIR;
|
||||
final boolean isSpecial = !isDirectory && (mode & LibC.S_IFREG) == 0;
|
||||
final long size = mySharedMem.getLong(mySizeOffset);
|
||||
final long mTime1 = SystemInfo.is32Bit ? mySharedMem.getInt(myTimeOffset) : mySharedMem.getLong(myTimeOffset);
|
||||
final long mTime2 = SystemInfo.is32Bit ? mySharedMem.getInt(myTimeOffset + 4) : mySharedMem.getLong(myTimeOffset + 8);
|
||||
final long mTime = mTime1 * 1000 + mTime2 / 1000000;
|
||||
@FileAttributes.Permissions final int permissions = mode & LibC.PERM_MASK;
|
||||
return new FileAttributes(isDirectory, isSpecial, isSymlink, size, mTime, permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -358,12 +406,20 @@ public class FileSystemUtil {
|
||||
public void setPermissions(@NotNull final String path, final int permissions) throws Exception {
|
||||
myLibC.chmod(path, permissions & LibC.PERM_MASK);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "JnaUnix";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StandardMediatorImpl implements Mediator {
|
||||
// from java.io.FileSystem
|
||||
private static final int BA_REGULAR = 0x02;
|
||||
private static final int BA_DIRECTORY = 0x04;
|
||||
private static final int BA_HIDDEN = 0x08;
|
||||
|
||||
private final Object myFileSystem;
|
||||
private final Method myGetBooleanAttributes;
|
||||
@@ -393,16 +449,18 @@ public class FileSystemUtil {
|
||||
if (myFileSystem != null) {
|
||||
final int flags = (Integer)myGetBooleanAttributes.invoke(myFileSystem, file);
|
||||
if (flags != 0) {
|
||||
final boolean isDirectory = (flags & BA_DIRECTORY) != 0;
|
||||
final boolean isSpecial = (flags & (BA_REGULAR | BA_DIRECTORY)) == 0;
|
||||
return new FileAttributes(isDirectory, false, isSpecial, file.length(), file.lastModified(), file.canWrite());
|
||||
final boolean isDirectory = isSet(flags, BA_DIRECTORY);
|
||||
final boolean isSpecial = notSet(flags, BA_REGULAR | BA_DIRECTORY);
|
||||
final boolean isHidden = isSet(flags, BA_HIDDEN);
|
||||
return new FileAttributes(isDirectory, isSpecial, false, isHidden, file.length(), file.lastModified(), file.canWrite());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (file.exists()) {
|
||||
final boolean isDirectory = file.isDirectory();
|
||||
final boolean isSpecial = !isDirectory && !file.isFile();
|
||||
return new FileAttributes(isDirectory, false, isSpecial, file.length(), file.lastModified(), file.canWrite());
|
||||
final boolean isHidden = file.isHidden();
|
||||
return new FileAttributes(isDirectory, isSpecial, false, isHidden, file.length(), file.lastModified(), file.canWrite());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,5 +475,11 @@ public class FileSystemUtil {
|
||||
@Override
|
||||
public void setPermissions(@NotNull final String path, final int permissions) throws Exception {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "fallback";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1953,6 +1953,22 @@ public class StringUtil extends StringUtilRt {
|
||||
return res;
|
||||
}
|
||||
|
||||
public static int getOccurrenceCount(@NotNull String text, final String s) {
|
||||
int res = 0;
|
||||
int i = 0;
|
||||
while (i < text.length()) {
|
||||
i = text.indexOf(s, i);
|
||||
if (i >= 0) {
|
||||
res++;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String fixVariableNameDerivedFromPropertyName(@NotNull String name) {
|
||||
char c = name.charAt(0);
|
||||
|
||||
@@ -19,7 +19,11 @@ package com.intellij.util;
|
||||
* @since 27.03.2012
|
||||
*/
|
||||
public class BitUtil {
|
||||
public static boolean isSet(final int mask, final int flag) {
|
||||
return (mask & flag) == flag;
|
||||
public static boolean isSet(final int value, final int flag) {
|
||||
return (value & flag) == flag;
|
||||
}
|
||||
|
||||
public static boolean notSet(final int value, final int mask) {
|
||||
return (value & mask) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.util.io;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class FileAttributesNio2ReadingTest extends FileAttributesReadingTest {
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
System.setProperty(FileSystemUtil.FORCE_USE_NIO2_KEY, "true");
|
||||
FileSystemUtil.resetMediator();
|
||||
assertEquals("NIO2", FileSystemUtil.getMediatorName());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
System.setProperty(FileSystemUtil.FORCE_USE_NIO2_KEY, "");
|
||||
FileSystemUtil.resetMediator();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
assumeTrue(SystemInfo.isJavaVersionAtLeast("1.7"));
|
||||
super.setUp();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.util.io;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class FileAttributesReadingTest {
|
||||
private final byte[] myTestData = new byte[]{'t', 'e', 's', 't'};
|
||||
private File myTempDirectory;
|
||||
|
||||
@BeforeClass
|
||||
public static void checkMediator() throws Exception {
|
||||
final String expectedName = SystemInfo.isWindows ? "IdeaWin32" : "JnaUnix";
|
||||
assertEquals(expectedName, FileSystemUtil.getMediatorName());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
myTempDirectory = FileUtil.createTempDirectory(getClass().getName(), ".tmp");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (myTempDirectory != null) {
|
||||
FileUtil.delete(myTempDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void regularFile() throws Exception {
|
||||
final File file = FileUtil.createTempFile(myTempDirectory, "test.", ".txt", true);
|
||||
FileUtil.writeToFile(file, myTestData);
|
||||
|
||||
final FileAttributes attributes = getAttributes(file);
|
||||
assertEquals(0, attributes.type);
|
||||
assertEquals(myTestData.length, attributes.length);
|
||||
assertTimestampEquals(file.lastModified(), attributes.lastModified);
|
||||
assertTrue(attributes.isWritable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void directory() throws Exception {
|
||||
final File file = FileUtil.createTempDirectory(myTempDirectory, "test.", ".tmp");
|
||||
|
||||
final FileAttributes attributes = getAttributes(file);
|
||||
assertEquals(FileAttributes.DIRECTORY, attributes.type);
|
||||
assertEquals(file.length(), attributes.length);
|
||||
assertTimestampEquals(file.lastModified(), attributes.lastModified);
|
||||
assertTrue(attributes.isWritable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void special() throws Exception {
|
||||
assumeTrue(SystemInfo.isUnix);
|
||||
final File file = new File("/dev/null");
|
||||
|
||||
final FileAttributes attributes = getAttributes(file);
|
||||
assertEquals(FileAttributes.SPECIAL, attributes.type);
|
||||
assertEquals(0, attributes.length);
|
||||
assertTrue(attributes.isWritable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linkToFile() throws Exception {
|
||||
final File file = FileUtil.createTempFile(myTempDirectory, "test.", ".txt", true);
|
||||
FileUtil.writeToFile(file, myTestData);
|
||||
assertTrue(file.setLastModified(file.lastModified() - 5000));
|
||||
assertTrue(file.setWritable(false, false));
|
||||
final File link = IoTestUtil.createTempLink(file.getPath(), new File(myTempDirectory, "link").getPath());
|
||||
|
||||
final FileAttributes attributes = getAttributes(link);
|
||||
assertEquals(FileAttributes.SYM_LINK, attributes.type);
|
||||
assertEquals(myTestData.length, attributes.length);
|
||||
assertTimestampEquals(file.lastModified(), attributes.lastModified);
|
||||
assertFalse(attributes.isWritable());
|
||||
|
||||
final String target = FileSystemUtil.resolveSymLink(link);
|
||||
assertEquals(file.getPath(), target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doubleLink() throws Exception {
|
||||
final File file = FileUtil.createTempFile(myTempDirectory, "test.", ".txt", true);
|
||||
FileUtil.writeToFile(file, myTestData);
|
||||
assertTrue(file.setLastModified(file.lastModified() - 5000));
|
||||
assertTrue(file.setWritable(false, false));
|
||||
final File link1 = IoTestUtil.createTempLink(file.getPath(), new File(myTempDirectory, "link1").getPath());
|
||||
final File link2 = IoTestUtil.createTempLink(link1.getPath(), new File(myTempDirectory, "link2").getPath());
|
||||
|
||||
final FileAttributes attributes = getAttributes(link2);
|
||||
assertEquals(FileAttributes.SYM_LINK, attributes.type);
|
||||
assertEquals(myTestData.length, attributes.length);
|
||||
assertTimestampEquals(file.lastModified(), attributes.lastModified);
|
||||
assertFalse(attributes.isWritable());
|
||||
|
||||
final String target = FileSystemUtil.resolveSymLink(link2);
|
||||
assertEquals(file.getPath(), target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linkToDirectory() throws Exception {
|
||||
final File file = FileUtil.createTempDirectory(myTempDirectory, "test.", ".tmp");
|
||||
if (SystemInfo.isUnix) assertTrue(file.setWritable(false, false));
|
||||
assertTrue(file.setLastModified(file.lastModified() - 5000));
|
||||
final File link = IoTestUtil.createTempLink(file.getPath(), new File(myTempDirectory, "link").getPath());
|
||||
|
||||
final FileAttributes attributes = getAttributes(link);
|
||||
assertEquals(FileAttributes.DIRECTORY | FileAttributes.SYM_LINK, attributes.type);
|
||||
assertEquals(file.length(), attributes.length);
|
||||
assertTimestampEquals(file.lastModified(), attributes.lastModified);
|
||||
if (SystemInfo.isUnix) assertFalse(attributes.isWritable());
|
||||
|
||||
final String target = FileSystemUtil.resolveSymLink(link);
|
||||
assertEquals(file.getPath(), target);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static FileAttributes getAttributes(@NotNull final File file) {
|
||||
final FileAttributes attributes = FileSystemUtil.getAttributes(file.getPath());
|
||||
assertNotNull(attributes);
|
||||
System.out.println(attributes);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private static void assertTimestampEquals(final long expected, final long actual) {
|
||||
final long roundedExpected = (expected / 1000) * 1000;
|
||||
final long roundedActual = (actual / 1000) * 1000;
|
||||
assertEquals("expected: " + expected + ", actual: " + actual,
|
||||
roundedExpected, roundedActual);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.util.io;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class IoTestUtil {
|
||||
// todo[r.sh] use NIO2 API after migration to JDK 7
|
||||
public static File createTempLink(final String target, final String link) throws InterruptedException, IOException {
|
||||
final boolean isAbsolute = SystemInfo.isUnix && StringUtil.startsWithChar(link, '/') ||
|
||||
SystemInfo.isWindows && link.matches("^[c-zC-Z]:[/\\\\].*$");
|
||||
final File linkFile = isAbsolute ? new File(link) : new File(FileUtil.getTempDirectory(), link);
|
||||
assertTrue(link, !linkFile.exists() || linkFile.delete());
|
||||
final File parentDir = linkFile.getParentFile();
|
||||
assertTrue("link=" + link + ", parent=" + parentDir, parentDir != null && (parentDir.isDirectory() || parentDir.mkdirs()));
|
||||
|
||||
final ProcessBuilder commandLine;
|
||||
if (SystemInfo.isWindows) {
|
||||
commandLine = new File(target).isDirectory()
|
||||
? new ProcessBuilder("cmd", "/C", "mklink", "/D", linkFile.getAbsolutePath(), target)
|
||||
: new ProcessBuilder("cmd", "/C", "mklink", linkFile.getAbsolutePath(), target);
|
||||
}
|
||||
else {
|
||||
commandLine = new ProcessBuilder("ln", "-s", target, linkFile.getAbsolutePath());
|
||||
}
|
||||
final int res = commandLine.start().waitFor();
|
||||
assertEquals(commandLine.command().toString(), 0, res);
|
||||
|
||||
final File targetFile = new File(target);
|
||||
assertEquals("target=" + target + ", link=" + linkFile, targetFile.exists(), linkFile.exists());
|
||||
return linkFile;
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -79,6 +79,8 @@ import java.util.List;
|
||||
* Time: 4:00 PM
|
||||
*/
|
||||
public class ChangesFragmentedDiffPanel implements Disposable {
|
||||
private static final int SHORT_DIFF_DIVIDER_POLYGONS_OFFSET = 2;
|
||||
|
||||
private final JPanel myPanel;
|
||||
private final Project myProject;
|
||||
private final JComponent myParent;
|
||||
@@ -346,7 +348,7 @@ public class ChangesFragmentedDiffPanel implements Disposable {
|
||||
}
|
||||
|
||||
private DiffPanel createPanel(final boolean horizontal) {
|
||||
final DiffPanel diffPanel = new DiffPanelImpl(null, myProject, false, horizontal){
|
||||
final DiffPanel diffPanel = new DiffPanelImpl(null, myProject, false, horizontal, SHORT_DIFF_DIVIDER_POLYGONS_OFFSET){
|
||||
@Override
|
||||
protected DiffPanelState createDiffPanelState(@NotNull Disposable parentDisposable) {
|
||||
return new FragmentedDiffPanelState(this, myProject, ! horizontal, parentDisposable);
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ public class VcsDirtyScopeVfsListener implements ApplicationComponent, BulkFileL
|
||||
if (!file.isInLocalFileSystem()) { continue; }
|
||||
dirtyFilesAndDirs.add(file, true);
|
||||
} else if (event instanceof VFileMoveEvent || event instanceof VFilePropertyChangeEvent) {
|
||||
dirtyFilesAndDirs.add(file, false);
|
||||
dirtyFilesAndDirs.add(file, true);
|
||||
}
|
||||
}
|
||||
// and notify VCSDirtyScopeManager
|
||||
|
||||
+2
-1
@@ -19,6 +19,7 @@ import com.intellij.psi.PsiAnnotation;
|
||||
import com.intellij.psi.PsiAnnotationMethod;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
enum InitializerRequirement {
|
||||
@@ -32,7 +33,7 @@ enum InitializerRequirement {
|
||||
InitializerRequirement r = NONE_REQUIRED;
|
||||
final PsiMethod[] methods = psiClass.getMethods();
|
||||
for (PsiMethod method : methods) {
|
||||
if (method instanceof PsiAnnotationMethod) {
|
||||
if (PsiUtil.isAnnotationMethod(method)) {
|
||||
final PsiAnnotationMethod annotationMethod = (PsiAnnotationMethod)method;
|
||||
if (annotationMethod.getDefaultValue() == null) {
|
||||
if (PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(annotationMethod.getName())) {
|
||||
|
||||
+3
-2
@@ -32,6 +32,7 @@ import com.intellij.designer.designSurface.selection.NonResizeSelectionDecorator
|
||||
import com.intellij.designer.designSurface.tools.ComponentCreationFactory;
|
||||
import com.intellij.designer.designSurface.tools.ComponentPasteFactory;
|
||||
import com.intellij.designer.model.RadComponent;
|
||||
import com.intellij.designer.model.RadVisualComponent;
|
||||
import com.intellij.designer.model.WrapInProvider;
|
||||
import com.intellij.designer.palette.DefaultPaletteItem;
|
||||
import com.intellij.designer.palette.PaletteGroup;
|
||||
@@ -178,7 +179,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel {
|
||||
createRenderer(parser.getLayoutXmlText(), new MyThrowable(), new ThrowableConsumer<RenderSession, Throwable>() {
|
||||
@Override
|
||||
public void consume(RenderSession session) throws Throwable {
|
||||
RootView rootView = new RootView(session.getImage(), 30, 20);
|
||||
RootView rootView = new RootView(30, 20, session.getImage());
|
||||
try {
|
||||
parser.updateRootComponent(session, rootView);
|
||||
}
|
||||
@@ -360,7 +361,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel {
|
||||
|
||||
private void removeNativeRoot() {
|
||||
if (myRootComponent != null) {
|
||||
Component component = ((RadViewComponent)myRootComponent).getNativeComponent();
|
||||
Component component = ((RadVisualComponent)myRootComponent).getNativeComponent();
|
||||
if (component != null) {
|
||||
myLayeredPane.remove(component.getParent());
|
||||
}
|
||||
|
||||
+11
-128
@@ -15,119 +15,38 @@
|
||||
*/
|
||||
package com.intellij.android.designer.designSurface;
|
||||
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.designer.designSurface.DesignerEditorPanel;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiTreeChangeAdapter;
|
||||
import com.intellij.psi.PsiTreeChangeEvent;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.containers.ComparatorUtil;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Alexander Lobas
|
||||
*/
|
||||
public class ExternalPSIChangeListener extends PsiTreeChangeAdapter {
|
||||
private final Alarm myAlarm = new Alarm();
|
||||
private final AndroidDesignerEditorPanel myDesigner;
|
||||
private final PsiFile myFile;
|
||||
private final int myDelayMillis;
|
||||
private final Runnable myRunnable;
|
||||
private volatile boolean myRunState;
|
||||
private volatile boolean myInitialize;
|
||||
private String myContent;
|
||||
public class ExternalPSIChangeListener extends com.intellij.designer.designSurface.ExternalPSIChangeListener {
|
||||
private VirtualFile[] myResourceDepends;
|
||||
private boolean myUpdateRenderer;
|
||||
|
||||
public ExternalPSIChangeListener(AndroidDesignerEditorPanel designer, PsiFile file, int delayMillis, Runnable runnable) {
|
||||
myDesigner = designer;
|
||||
myFile = file;
|
||||
myDelayMillis = delayMillis;
|
||||
myRunnable = runnable;
|
||||
myContent = myDesigner.getEditorText();
|
||||
PsiManager.getInstance(myDesigner.getProject()).addPsiTreeChangeListener(this);
|
||||
}
|
||||
|
||||
public void setInitialize() {
|
||||
myInitialize = true;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (!myRunState) {
|
||||
myRunState = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
PsiManager.getInstance(myDesigner.getProject()).removePsiTreeChangeListener(this);
|
||||
stop();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (myRunState) {
|
||||
myRunState = false;
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
if (!myRunState) {
|
||||
start();
|
||||
if (!ComparatorUtil.equalsNullable(myContent, myDesigner.getEditorText()) || myDesigner.getRootComponent() == null) {
|
||||
myUpdateRenderer = false;
|
||||
addRequest();
|
||||
}
|
||||
myContent = null;
|
||||
}
|
||||
public ExternalPSIChangeListener(DesignerEditorPanel designer, PsiFile file, int delayMillis, Runnable runnable) {
|
||||
super(designer, file, delayMillis, runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
if (myRunState) {
|
||||
stop();
|
||||
myContent = myDesigner.getEditorText();
|
||||
}
|
||||
|
||||
myUpdateRenderer = false;
|
||||
super.deactivate();
|
||||
|
||||
if (!myDesigner.getProject().isDisposed()) {
|
||||
myResourceDepends = AndroidFacet.getInstance(myDesigner.getModule()).getLocalResourceManager().getAllResourceDirs();
|
||||
}
|
||||
}
|
||||
|
||||
public void addRequest() {
|
||||
addRequest(myRunnable);
|
||||
}
|
||||
@Override
|
||||
protected void updatePsi(PsiTreeChangeEvent event) {
|
||||
boolean runState = myRunState;
|
||||
super.updatePsi(event);
|
||||
|
||||
public boolean isUpdateRenderer() {
|
||||
return myUpdateRenderer;
|
||||
}
|
||||
|
||||
public void addRequest(final Runnable runnable) {
|
||||
clear();
|
||||
myAlarm.addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myRunState && myInitialize && !myDesigner.getProject().isDisposed()) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
}, myDelayMillis, ModalityState.stateForComponent(myDesigner));
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
myAlarm.cancelAllRequests();
|
||||
}
|
||||
|
||||
private void updatePsi(PsiTreeChangeEvent event) {
|
||||
if (myRunState) {
|
||||
if (myFile == event.getFile()) {
|
||||
addRequest();
|
||||
}
|
||||
}
|
||||
else if (myResourceDepends != null && !myUpdateRenderer) {
|
||||
if (!runState && myResourceDepends != null && !myUpdateRenderer) {
|
||||
PsiFile psiFile = event.getFile();
|
||||
if (psiFile == null) {
|
||||
return;
|
||||
@@ -144,40 +63,4 @@ public class ExternalPSIChangeListener extends PsiTreeChangeAdapter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PSI
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void childAdded(@NotNull PsiTreeChangeEvent event) {
|
||||
updatePsi(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childRemoved(@NotNull PsiTreeChangeEvent event) {
|
||||
updatePsi(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childReplaced(@NotNull PsiTreeChangeEvent event) {
|
||||
updatePsi(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childMoved(@NotNull PsiTreeChangeEvent event) {
|
||||
updatePsi(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
|
||||
updatePsi(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChanged(@NotNull PsiTreeChangeEvent event) {
|
||||
updatePsi(event);
|
||||
}
|
||||
}
|
||||
+4
-15
@@ -24,26 +24,16 @@ import java.util.List;
|
||||
/**
|
||||
* @author Alexander Lobas
|
||||
*/
|
||||
public class RootView extends JComponent {
|
||||
private int myX;
|
||||
private int myY;
|
||||
private BufferedImage myImage;
|
||||
public class RootView extends com.intellij.designer.designSurface.RootView {
|
||||
private List<EmptyRegion> myEmptyRegions;
|
||||
|
||||
public RootView(BufferedImage image, int x, int y) {
|
||||
myX = x;
|
||||
myY = y;
|
||||
setImage(image);
|
||||
}
|
||||
|
||||
public BufferedImage getImage() {
|
||||
return myImage;
|
||||
public RootView(int x, int y, BufferedImage image) {
|
||||
super(x, y, image);
|
||||
}
|
||||
|
||||
public void setImage(BufferedImage image) {
|
||||
myImage = image;
|
||||
super.setImage(image);
|
||||
myEmptyRegions = new ArrayList<EmptyRegion>();
|
||||
setBounds(myX, myY, image.getWidth(), image.getHeight());
|
||||
}
|
||||
|
||||
public void addEmptyRegion(int x, int y, int width, int height) {
|
||||
@@ -61,7 +51,6 @@ public class RootView extends JComponent {
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
g.drawImage(myImage, 0, 0, null);
|
||||
|
||||
for (EmptyRegion r : myEmptyRegions) {
|
||||
g.setColor(r.myColor);
|
||||
|
||||
+10
-12
@@ -51,8 +51,8 @@ import org.jetbrains.android.actions.CreateXmlResourceDialog;
|
||||
import org.jetbrains.android.dom.resources.ResourceElement;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.facet.AndroidRootUtil;
|
||||
import org.jetbrains.android.resourceManagers.FileResourceProcessor;
|
||||
import org.jetbrains.android.resourceManagers.ResourceManager;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidResourceUtil;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
@@ -603,25 +603,23 @@ public class ResourceDialog extends DialogWrapper implements TreeSelectionListen
|
||||
public ResourceGroup(ResourceType type, ResourceManager manager) {
|
||||
myType = type;
|
||||
|
||||
String resourceType = type.getName();
|
||||
final String resourceType = type.getName();
|
||||
|
||||
Collection<String> resourceNames = manager.getValueResourceNames(resourceType);
|
||||
for (String resourceName : resourceNames) {
|
||||
myItems.add(new ResourceItem(this, resourceName, null, RESOURCE_ITEM_ICON));
|
||||
}
|
||||
final Set<String> fileNames = new HashSet<String>();
|
||||
|
||||
Set<String> fileNames = new HashSet<String>();
|
||||
List<VirtualFile> dirs = manager.getResourceSubdirs(resourceType);
|
||||
for (VirtualFile dir : dirs) {
|
||||
for (VirtualFile resourceFile : dir.getChildren()) {
|
||||
if (!resourceFile.isDirectory()) {
|
||||
String fileName = AndroidCommonUtils.getResourceName(resourceType, resourceFile.getName());
|
||||
if (fileNames.add(fileName)) {
|
||||
myItems.add(new ResourceItem(this, fileName, resourceFile, resourceFile.getFileType().getIcon()));
|
||||
}
|
||||
manager.processFileResources(resourceType, new FileResourceProcessor() {
|
||||
@Override
|
||||
public boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
|
||||
if (fileNames.add(resName)) {
|
||||
myItems.add(new ResourceItem(ResourceGroup.this, resName, resFile, resFile.getFileType().getIcon()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (type == ResourceType.ID) {
|
||||
for (String id : manager.getIds()) {
|
||||
|
||||
@@ -61,7 +61,7 @@ public class AndroidCommonUtils {
|
||||
private static final Pattern ERROR_PATTERN = Pattern.compile(".*error.*");
|
||||
private static final Pattern EXCEPTION_PATTERN = Pattern.compile(".*exception.*");
|
||||
|
||||
private static final Pattern R_PATTERN = Pattern.compile("R(\\$.*)?\\.class");
|
||||
public static final Pattern R_PATTERN = Pattern.compile("R(\\$.*)?\\.class");
|
||||
private static final Pattern MANIFEST_PATTERN = Pattern.compile("Manifest(\\$.*)?\\.class");
|
||||
private static final String BUILD_CONFIG_CLASS_NAME = "BuildConfig.class";
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
<compiler implementation="org.jetbrains.android.compiler.AndroidPngFilesCachingCompiler"/>
|
||||
<compiler implementation="org.jetbrains.android.compiler.AndroidResourcesPackagingCompiler"/>
|
||||
<compiler implementation="org.jetbrains.android.compiler.AndroidPackagingCompiler"/>
|
||||
<compiler.makeDependencyProcessor implementation="org.jetbrains.android.compiler.AndroidDependencyProcessor"/>
|
||||
|
||||
<completion.contributor language="XML" implementationClass="org.jetbrains.android.AndroidCompletionContributor"
|
||||
id="compositieAttributeValues" order="first"/>
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package org.jetbrains.android.compiler;
|
||||
|
||||
import com.intellij.compiler.DependencyProcessor;
|
||||
import com.intellij.compiler.make.*;
|
||||
import com.intellij.facet.ProjectFacetManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.compiler.CompileContext;
|
||||
import com.intellij.openapi.compiler.ex.CompileContextEx;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidDependencyProcessor implements DependencyProcessor {
|
||||
@Override
|
||||
public void processDependencies(final CompileContext context, int classQualifiedName, final CachingSearcher searcher)
|
||||
throws CacheCorruptedException {
|
||||
if (!(context instanceof CompileContextEx)) {
|
||||
return;
|
||||
}
|
||||
final Project project = context.getProject();
|
||||
|
||||
if (!ProjectFacetManager.getInstance(project).hasFacets(AndroidFacet.ID)) {
|
||||
return;
|
||||
}
|
||||
final DependencyCache depCache = ((CompileContextEx)context).getDependencyCache();
|
||||
final Cache cache = depCache.getCache();
|
||||
final String path = cache.getPath(classQualifiedName);
|
||||
final String classFileName = new File(path).getName();
|
||||
|
||||
if (!AndroidCommonUtils.R_PATTERN.matcher(classFileName).matches()) {
|
||||
return;
|
||||
}
|
||||
final String qName = depCache.resolve(classQualifiedName);
|
||||
final int idx = qName.indexOf('$');
|
||||
final String topLevelClassName = idx < 0 ? qName : qName.substring(0, idx);
|
||||
final Set<String> qNamesToMark = new HashSet<String>();
|
||||
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final PsiClass[] classes =
|
||||
JavaPsiFacade.getInstance(project).findClasses(topLevelClassName, GlobalSearchScope.allScope(project));
|
||||
|
||||
for (PsiClass aClass : classes) {
|
||||
final Collection<PsiReference> references = searcher.findReferences(aClass, true);
|
||||
|
||||
for (PsiReference reference : references) {
|
||||
final PsiClass ownerClass = getOwnerClass(reference.getElement());
|
||||
if (ownerClass != null && !ownerClass.equals(aClass)) {
|
||||
final String ownerClassQName = ownerClass.getQualifiedName();
|
||||
|
||||
if (ownerClassQName != null) {
|
||||
qNamesToMark.add(ownerClassQName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (String toMark : qNamesToMark) {
|
||||
final int qualifiedName = depCache.getSymbolTable().getId(toMark);
|
||||
depCache.markClass(qualifiedName);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClass getOwnerClass(PsiElement element) {
|
||||
while (!(element instanceof PsiFile)) {
|
||||
if (element instanceof PsiClass && element.getParent() instanceof PsiJavaFile) {
|
||||
return (PsiClass)element;
|
||||
}
|
||||
element = element.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+17
-26
@@ -4,11 +4,8 @@ import com.android.resources.ResourceType;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.intellij.openapi.compiler.ValidityState;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.ContentIterator;
|
||||
import com.intellij.openapi.roots.impl.FileIndexImplUtil;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileFilter;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.android.dom.resources.DeclareStyleable;
|
||||
@@ -16,6 +13,7 @@ import org.jetbrains.android.dom.resources.ResourceElement;
|
||||
import org.jetbrains.android.dom.resources.Resources;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.facet.AndroidRootUtil;
|
||||
import org.jetbrains.android.resourceManagers.FileResourceProcessor;
|
||||
import org.jetbrains.android.resourceManagers.LocalResourceManager;
|
||||
import org.jetbrains.android.sdk.AndroidPlatform;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
@@ -74,31 +72,24 @@ public class ResourceNamesValidityState implements ValidityState {
|
||||
}
|
||||
}
|
||||
|
||||
for (final VirtualFile subdir : manager.getResourceSubdirs(null)) {
|
||||
final String subdirName = subdir.getName();
|
||||
final int index = subdirName.indexOf('-');
|
||||
final String typeName = index >= 0 ? subdirName.substring(0, index) : subdirName;
|
||||
final ResourceType type = ResourceType.getEnum(typeName);
|
||||
final boolean idProvidingResource = type != null && ArrayUtil.find(AndroidCommonUtils.ID_PROVIDING_RESOURCE_TYPES, type) >= 0;
|
||||
manager.processFileResources(null, new FileResourceProcessor() {
|
||||
@Override
|
||||
public boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
|
||||
final ResourceType type = ResourceType.getEnum(resFolderType);
|
||||
final boolean idProvidingResource = type != null && ArrayUtil.find(AndroidCommonUtils.ID_PROVIDING_RESOURCE_TYPES, type) >= 0;
|
||||
|
||||
FileIndexImplUtil.iterateRecursively(subdir, VirtualFileFilter.ALL, new ContentIterator() {
|
||||
@Override
|
||||
public boolean processFile(VirtualFile fileOrDir) {
|
||||
if (!fileOrDir.isDirectory()) {
|
||||
ResourceFileData data = myResources.get(fileOrDir.getPath());
|
||||
if (data == null) {
|
||||
data = new ResourceFileData();
|
||||
myResources.put(fileOrDir.getPath(), data);
|
||||
}
|
||||
|
||||
if (idProvidingResource) {
|
||||
data.setTimestamp(fileOrDir.getTimeStamp());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
ResourceFileData data = myResources.get(resFile.getPath());
|
||||
if (data == null) {
|
||||
data = new ResourceFileData();
|
||||
myResources.put(resFile.getPath(), data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (idProvidingResource) {
|
||||
data.setTimestamp(resFile.getTimeStamp());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void addValueResources(VirtualFile file,
|
||||
|
||||
+9
-7
@@ -33,9 +33,9 @@ import org.jetbrains.android.dom.resources.ResourceValue;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.inspections.CreateFileResourceQuickFix;
|
||||
import org.jetbrains.android.inspections.CreateValueResourceQuickFix;
|
||||
import org.jetbrains.android.resourceManagers.FileResourceProcessor;
|
||||
import org.jetbrains.android.resourceManagers.LocalResourceManager;
|
||||
import org.jetbrains.android.resourceManagers.ResourceManager;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidResourceUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -164,13 +164,15 @@ public class ResourceReferenceConverter extends ResolvingConverter<ResourceValue
|
||||
final Set<String> result = new HashSet<String>();
|
||||
final LocalResourceManager manager = facet.getLocalResourceManager();
|
||||
|
||||
for (VirtualFile resSubdir : manager.getResourceSubdirs(null)) {
|
||||
final String resType = AndroidCommonUtils.getResourceTypeByDirName(resSubdir.getName());
|
||||
|
||||
if (resType != null && ResourceType.getEnum(resType) != null) {
|
||||
result.add(resType);
|
||||
manager.processFileResources(null, new FileResourceProcessor() {
|
||||
@Override
|
||||
public boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
|
||||
if (ResourceType.getEnum(resFolderType) != null) {
|
||||
result.add(resFolderType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
result.addAll(manager.getValueResourceTypes());
|
||||
if (manager.getIds().size() > 0) {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.jetbrains.android.resourceManagers;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public interface FileResourceProcessor {
|
||||
boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType);
|
||||
}
|
||||
@@ -75,6 +75,30 @@ public abstract class ResourceManager {
|
||||
@Nullable
|
||||
public abstract VirtualFile getResourceDir();
|
||||
|
||||
public boolean processFileResources(@Nullable String resourceType, @NotNull FileResourceProcessor processor) {
|
||||
return processFileResources(resourceType, processor, true);
|
||||
}
|
||||
|
||||
public boolean processFileResources(@Nullable String resourceType, @NotNull FileResourceProcessor processor, boolean publicOnly) {
|
||||
for (VirtualFile resSubdir : getResourceSubdirs(resourceType)) {
|
||||
final String resType = AndroidCommonUtils.getResourceTypeByDirName(resSubdir.getName());
|
||||
|
||||
if (resType != null) {
|
||||
assert resourceType == null || resourceType.equals(resType);
|
||||
for (VirtualFile resFile : resSubdir.getChildren()) {
|
||||
final String resName = AndroidCommonUtils.getResourceName(resType, resFile.getName());
|
||||
|
||||
if (!resFile.isDirectory() && (!publicOnly || isResourcePublic(resType, resName))) {
|
||||
if (!processor.process(resFile, resName, resType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isResourceDir(@NotNull VirtualFile dir) {
|
||||
return dir.equals(getResourceDir());
|
||||
}
|
||||
@@ -84,38 +108,44 @@ public abstract class ResourceManager {
|
||||
return VirtualFile.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
protected boolean isResourcePublic(@NotNull String type, @NotNull String name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<VirtualFile> getResourceSubdirs(@Nullable String resourceType) {
|
||||
return AndroidResourceUtil.getResourceSubdirs(resourceType, getAllResourceDirs());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<PsiFile> findResourceFiles(@NotNull String resType,
|
||||
@Nullable String resName,
|
||||
boolean distinguishDelimetersInName,
|
||||
@NotNull String... extensions) {
|
||||
List<PsiFile> result = new ArrayList<PsiFile>();
|
||||
Set<String> extensionSet = new HashSet<String>();
|
||||
public List<PsiFile> findResourceFiles(@NotNull final String resType1,
|
||||
@Nullable final String resName1,
|
||||
final boolean distinguishDelimetersInName,
|
||||
@NotNull final String... extensions) {
|
||||
final List<PsiFile> result = new ArrayList<PsiFile>();
|
||||
final Set<String> extensionSet = new HashSet<String>();
|
||||
addAll(extensionSet, extensions);
|
||||
for (VirtualFile dir : getResourceSubdirs(resType)) {
|
||||
for (final VirtualFile resFile : dir.getChildren()) {
|
||||
String extension = resFile.getExtension();
|
||||
if (extensions.length == 0 || extensionSet.contains(extension)) {
|
||||
String s = AndroidCommonUtils.getResourceName(resType, resFile.getName());
|
||||
if (resName == null || AndroidUtils.equal(resName, s, distinguishDelimetersInName)) {
|
||||
PsiFile file = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() {
|
||||
@Nullable
|
||||
public PsiFile compute() {
|
||||
return PsiManager.getInstance(myModule.getProject()).findFile(resFile);
|
||||
}
|
||||
});
|
||||
if (file != null) {
|
||||
result.add(file);
|
||||
|
||||
processFileResources(resType1, new FileResourceProcessor() {
|
||||
@Override
|
||||
public boolean process(@NotNull final VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
|
||||
final String extension = resFile.getExtension();
|
||||
|
||||
if ((extensions.length == 0 || extensionSet.contains(extension)) &&
|
||||
(resName1 == null || AndroidUtils.equal(resName1, resName, distinguishDelimetersInName))) {
|
||||
final PsiFile file = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() {
|
||||
@Nullable
|
||||
public PsiFile compute() {
|
||||
return PsiManager.getInstance(myModule.getProject()).findFile(resFile);
|
||||
}
|
||||
});
|
||||
if (file != null) {
|
||||
result.add(file);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -171,7 +201,14 @@ public abstract class ResourceManager {
|
||||
if (!resources.isValid() || myModule.isDisposed() || myModule.getProject().isDisposed()) {
|
||||
return;
|
||||
}
|
||||
result.addAll(AndroidResourceUtil.getValueResourcesFromElement(resourceType, resources));
|
||||
final List<ResourceElement> valueResources = AndroidResourceUtil.getValueResourcesFromElement(resourceType, resources);
|
||||
for (ResourceElement valueResource : valueResources) {
|
||||
final String resName = valueResource.getName().getValue();
|
||||
|
||||
if (resName != null && isResourcePublic(resourceType, resName)) {
|
||||
result.add(valueResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -207,15 +244,16 @@ public abstract class ResourceManager {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<String> getFileResourcesNames(@NotNull String resourceType) {
|
||||
Set<String> result = new HashSet<String>();
|
||||
List<VirtualFile> dirs = getResourceSubdirs(resourceType);
|
||||
for (VirtualFile dir : dirs) {
|
||||
for (VirtualFile resourceFile : dir.getChildren()) {
|
||||
if (resourceFile.isDirectory()) continue;
|
||||
result.add(AndroidCommonUtils.getResourceName(resourceType, resourceFile.getName()));
|
||||
public Set<String> getFileResourcesNames(@NotNull final String resourceType) {
|
||||
final Set<String> result = new HashSet<String>();
|
||||
|
||||
processFileResources(resourceType, new FileResourceProcessor() {
|
||||
@Override
|
||||
public boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
|
||||
result.add(resName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -269,7 +307,9 @@ public abstract class ResourceManager {
|
||||
|
||||
if (entries != null) {
|
||||
for (ResourceEntry entry : entries) {
|
||||
result.add(entry);
|
||||
if (isResourcePublic(entry.getType(), entry.getName())) {
|
||||
result.add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,6 +333,10 @@ public abstract class ResourceManager {
|
||||
// searches only declarations such as "@+id/..."
|
||||
@Nullable
|
||||
public List<PsiElement> findIdDeclarations(@NotNull final String id) {
|
||||
if (!isResourcePublic(ResourceType.ID.getName(), id)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<PsiElement> declarations = new ArrayList<PsiElement>();
|
||||
final Collection<VirtualFile> files =
|
||||
FileBasedIndex.getInstance().getContainingFiles(AndroidIdIndex.INDEX_ID, id, GlobalSearchScope.allScope(myModule.getProject()));
|
||||
@@ -357,9 +401,13 @@ public abstract class ResourceManager {
|
||||
for (VirtualFile resSubdir : getResourceSubdirsToSearchIds()) {
|
||||
for (VirtualFile resFile : resSubdir.getChildren()) {
|
||||
final Set<String> ids = file2ids.get(resFile);
|
||||
|
||||
|
||||
if (ids != null) {
|
||||
result.addAll(ids);
|
||||
for (String id : ids) {
|
||||
if (isResourcePublic(ResourceType.ID.getName(), id)) {
|
||||
result.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,25 +16,84 @@
|
||||
package org.jetbrains.android.resourceManagers;
|
||||
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiField;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.xml.ConvertContext;
|
||||
import org.jetbrains.android.dom.attrs.AttributeDefinitions;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.sdk.AndroidPlatform;
|
||||
import org.jetbrains.android.sdk.AndroidTargetData;
|
||||
import org.jetbrains.android.util.AndroidResourceUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author coyote
|
||||
*/
|
||||
public class SystemResourceManager extends ResourceManager {
|
||||
private final AndroidPlatform myPlatform;
|
||||
private final Map<String, Set<String>> myPublicResourcesCache = new HashMap<String, Set<String>>();
|
||||
|
||||
public SystemResourceManager(@NotNull AndroidFacet facet, @NotNull AndroidPlatform androidPlatform) {
|
||||
super(facet);
|
||||
myPlatform = androidPlatform;
|
||||
final Module module = facet.getModule();
|
||||
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
buildPublicResourceCache(module);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void buildPublicResourceCache(@NotNull Module module) {
|
||||
final PsiClass rClass = JavaPsiFacade.getInstance(module.getProject())
|
||||
.findClass(SdkConstants.CLASS_R, module.getModuleWithDependenciesAndLibrariesScope(false));
|
||||
if (rClass == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (PsiClass resourceClass : rClass.getInnerClasses()) {
|
||||
final String resType = resourceClass.getName();
|
||||
|
||||
if (resType != null) {
|
||||
Set<String> resNameSet = myPublicResourcesCache.get(resType);
|
||||
|
||||
if (resNameSet == null) {
|
||||
resNameSet = new HashSet<String>();
|
||||
myPublicResourcesCache.put(resType, resNameSet);
|
||||
}
|
||||
|
||||
for (PsiField resField : resourceClass.getFields()) {
|
||||
final String resName = resField.getName();
|
||||
|
||||
if (resName != null) {
|
||||
resNameSet.add(resName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isResourcePublic(@NotNull String type, @NotNull String name) {
|
||||
final Set<String> fieldNames = myPublicResourcesCache.get(type);
|
||||
if (fieldNames == null || fieldNames.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
final String fieldName = AndroidResourceUtil.getFieldNameByResourceName(name);
|
||||
return fieldNames.contains(fieldName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<objectAnimator
|
||||
android:interpolator="@android:interpolator/platformInterpolator"
|
||||
android:interpolator="@android:interpolator/accelerate_cubic"
|
||||
android:valueFrom="100dp" android:valueTo="0dp"
|
||||
android:valueType="floatType"
|
||||
android:propertyName="translationX"
|
||||
android:duration="@android:integer/config_mediumAnimTime" />
|
||||
<animator
|
||||
android:interpolator="@android:interpolator/platformInterpolator"
|
||||
android:interpolator="@android:interpolator/accelerate_cubic"
|
||||
android:valueFrom="0.0" android:valueTo="1.0"
|
||||
android:valueType="floatType"
|
||||
android:propertyName="alpha"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<objectAnimator
|
||||
android:interpolator="@interpolator/myInterpolator"
|
||||
android:valueFrom="100dp" android:valueTo="0dp"
|
||||
android:valueType="floatType"
|
||||
android:propertyName="translationX"
|
||||
android:duration="@android:integer/config_mediumAnimTime" />
|
||||
<animator
|
||||
android:interpolator="@interpolator/myInterpolator"
|
||||
android:valueFrom="0.0" android:valueTo="1.0"
|
||||
android:valueType="floatType"
|
||||
android:propertyName="alpha"
|
||||
android:duration="@android:integer/config_mediumAnimTime" />
|
||||
</set>
|
||||
@@ -1,3 +1,3 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<TextView android:layout_alignBaseline="@android:id/no_permiss<caret>"/>
|
||||
<TextView android:layout_alignBaseline="@android:id/closeBut<caret>"/>
|
||||
</RelativeLayout>
|
||||
@@ -1,3 +1,3 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<TextView android:layout_alignBaseline="@android:id/no_permissions"/>
|
||||
<TextView android:layout_alignBaseline="@android:id/closeButton"/>
|
||||
</RelativeLayout>
|
||||
@@ -1,3 +1,3 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
style="@android:style/WindowTitleBackground">
|
||||
style="@android:style/MediaButton">
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,10 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="<error>@android:drawable/private</error>"/>
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:drawable/menuitem_background"/>
|
||||
</LinearLayout>
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="p1.p2">
|
||||
<application android:icon="@drawable/picture1">
|
||||
<activity android:name="MyActivity"/>
|
||||
</application>
|
||||
</manifest>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user