diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java index 76de9729c7e7..f883024fdc71 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java @@ -161,14 +161,16 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { synchronized (mySourcesToRecompile) { final TIntHashSet pathsToRecompile = mySourcesToRecompile.get(projectId); if (_forceCompile || pathsToRecompile != null && !pathsToRecompile.isEmpty()) { + if (ourDebugMode) { + System.out.println("Analysing potentially recompilable files for " + compiler.getDescription()); + } while (scopeSrcIterator.hasNext()) { final VirtualFile file = scopeSrcIterator.next(); if (!file.isValid()) { if (LOG.isDebugEnabled() || ourDebugMode) { - final String message = "Skipping invalid file " + file.getPresentableUrl(); - LOG.debug(message); + LOG.debug("Skipping invalid file " + file.getPresentableUrl()); if (ourDebugMode) { - System.out.println(message); + System.out.println("\t SKIPPED(INVALID) " + file.getPresentableUrl()); } } continue; @@ -177,17 +179,38 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { if (_forceCompile) { if (compiler.isCompilableFile(file, context) && !configuration.isExcludedFromCompilation(file)) { toCompile.add(file); + if (ourDebugMode) { + System.out.println("\t INCLUDED " + file.getPresentableUrl()); + } selectedForRecompilation.add(file); if (pathsToRecompile == null || !pathsToRecompile.contains(fileId)) { addSourceForRecompilation(projectId, file, null); } } + else { + if (ourDebugMode) { + System.out.println("\t NOT COMPILABLE OR EXCLUDED " + file.getPresentableUrl()); + } + } } else if (pathsToRecompile.contains(fileId)) { if (compiler.isCompilableFile(file, context) && !configuration.isExcludedFromCompilation(file)) { toCompile.add(file); + if (ourDebugMode) { + System.out.println("\t INCLUDED " + file.getPresentableUrl()); + } selectedForRecompilation.add(file); } + else { + if (ourDebugMode) { + System.out.println("\t NOT COMPILABLE OR EXCLUDED " + file.getPresentableUrl()); + } + } + } + else { + if (ourDebugMode) { + System.out.println("\t NOT INCLUDED " + file.getPresentableUrl()); + } } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java index 5a7b05dd3b1d..e3aafe432b11 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java @@ -28,9 +28,13 @@ import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.impl.source.jsp.jspJava.JspClass; import com.intellij.psi.util.PsiTypesUtil; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; +import java.util.Comparator; + public class CreateConstructorParameterFromFieldFix implements IntentionAction { private final SmartPsiElementPointer myField; @@ -76,8 +80,22 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction { aClass = getField().getContainingClass(); constructors = aClass.getConstructors(); } - for (int i = 0; i < constructors.length; i++){ - if (!addParameterToConstructor(project, file, editor, getField().getContainingClass().getConstructors()[i])) break; + Arrays.sort(constructors, new Comparator() { + @Override + public int compare(PsiMethod c1, PsiMethod c2) { + final PsiMethod cc1 = RefactoringUtil.getChainedConstructor(c1); + final PsiMethod cc2 = RefactoringUtil.getChainedConstructor(c2); + if (cc1 == c2) return 1; + if (cc2 == c1) return -1; + if (cc1 == null) { + return cc2 == null ? 0 : compare(c1, cc2); + } else { + return cc2 == null ? compare(cc1, c2) : compare(cc1, cc2); + } + } + }); + for (PsiMethod constructor : constructors) { + if (!addParameterToConstructor(project, file, editor, constructor)) break; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java index 7453b29a9cb3..b50a34e6d9c6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -339,7 +339,10 @@ public class JavaDocInfoGenerator { generateTypeParametersSection(buffer, result); } + @Nullable private static Pair> findInHierarchy(PsiClass psiClass, final DocTagLocator locator) { + final Pair> inClassComment = findInClassComment(psiClass, locator); + if (inClassComment != null) return inClassComment; for (final PsiClass superClass : psiClass.getSupers()) { final Pair> pair = findInClassComment(superClass, locator); if (pair != null) return pair; @@ -348,7 +351,7 @@ public class JavaDocInfoGenerator { final Pair> pair = findInClassComment(superInterface, locator); if (pair != null) return pair; } - return findInClassComment(psiClass, locator); + return null; } private static Pair> findInClassComment(final PsiClass psiClass, final DocTagLocator locator) { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index 9d373db01edc..705c7f0e195a 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -127,6 +127,9 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme correctedOffset = offset; } else if (!Character.isJavaIdentifierPart(text.charAt(correctedOffset))) { + if (text.charAt(correctedOffset) == ';') {//initially caret on the end of line + correctedOffset--; + } if (text.charAt(correctedOffset) != ')') { correctedOffset = offset; } diff --git a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ParameterData.java b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ParameterData.java index 4d7307edeeb3..5279cd3a3b25 100644 --- a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ParameterData.java +++ b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ParameterData.java @@ -25,7 +25,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PropertyUtil; -import org.jetbrains.annotations.Nullable; +import com.intellij.refactoring.util.RefactoringUtil; import java.util.Map; @@ -51,7 +51,7 @@ public class ParameterData { initParameterData(parameter, result); } - final PsiMethod chainedConstructor = getChainedConstructor(constructor); + final PsiMethod chainedConstructor = RefactoringUtil.getChainedConstructor(constructor); if (chainedConstructor != null) { final PsiCodeBlock constructorBody = constructor.getBody(); LOG.assertTrue(constructorBody != null); @@ -68,24 +68,6 @@ public class ParameterData { } } - @Nullable - public static PsiMethod getChainedConstructor(PsiMethod constructor) { - final PsiCodeBlock constructorBody = constructor.getBody(); - LOG.assertTrue(constructorBody != null); - final PsiStatement[] statements = constructorBody.getStatements(); - if (statements.length == 1 && statements[0] instanceof PsiExpressionStatement) { - final PsiExpression expression = ((PsiExpressionStatement)statements[0]).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; - final PsiReferenceExpression methodExpr = methodCallExpression.getMethodExpression(); - if ("this".equals(methodExpr.getReferenceName())) { - return (PsiMethod)methodExpr.resolve(); - } - } - } - return null; - } - private static ParameterData initParameterData(PsiParameter parameter, Map result) { JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(parameter.getProject()); final String paramName = parameter.getName(); diff --git a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java index 41f53f6631d7..f6b4b5e6463e 100644 --- a/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/replaceConstructorWithBuilder/ReplaceConstructorWithBuilderProcessor.java @@ -40,6 +40,7 @@ import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.replaceConstructorWithBuilder.usageInfo.ReplaceConstructorWithSettersChainInfo; import com.intellij.refactoring.util.FixableUsageInfo; import com.intellij.refactoring.util.FixableUsagesRefactoringProcessor; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewDescriptor; import com.intellij.util.IncorrectOperationException; @@ -234,7 +235,7 @@ public class ReplaceConstructorWithBuilderProcessor extends FixableUsagesRefacto if (myConstructors.length == 1) return myConstructors[0]; PsiMethod commonConstructor = null; for (PsiMethod constructor : myConstructors) { - final PsiMethod chainedConstructor = ParameterData.getChainedConstructor(constructor); + final PsiMethod chainedConstructor = RefactoringUtil.getChainedConstructor(constructor); if (chainedConstructor == null) { if (commonConstructor != null) { if (!isChained(commonConstructor, constructor)) { @@ -258,7 +259,7 @@ public class ReplaceConstructorWithBuilderProcessor extends FixableUsagesRefacto private static boolean isChained(PsiMethod first, PsiMethod last) { if (first == null) return false; if (first == last) return true; - return isChained(ParameterData.getChainedConstructor(first), last); + return isChained(RefactoringUtil.getChainedConstructor(first), last); } private String createMethodName() { diff --git a/java/java-impl/src/com/intellij/refactoring/util/FieldConflictsResolver.java b/java/java-impl/src/com/intellij/refactoring/util/FieldConflictsResolver.java index 9fbea01ed06b..974568a2a324 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/FieldConflictsResolver.java +++ b/java/java-impl/src/com/intellij/refactoring/util/FieldConflictsResolver.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.util; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; @@ -113,6 +114,13 @@ public class FieldConflictsResolver { final PsiMember member, @Nullable final PsiClass qualifyingClass) throws IncorrectOperationException { PsiManager manager = referenceExpression.getManager(); + PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(referenceExpression, PsiMethodCallExpression.class, true); + while ((methodCallExpression) != null) { + if (HighlightUtil.isSuperOrThisMethodCall(methodCallExpression)) { + return referenceExpression; + } + methodCallExpression = PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethodCallExpression.class, true); + } PsiReferenceExpression expressionFromText; final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); if (qualifyingClass == null) { diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java index 5cd57a03d9dd..9f82d897afce 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java @@ -53,6 +53,7 @@ import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.PackageWrapper; import com.intellij.refactoring.introduceField.ElementToWorkOn; import com.intellij.refactoring.introduceVariable.IntroduceVariableBase; +import com.intellij.refactoring.replaceConstructorWithBuilder.ParameterData; import com.intellij.usageView.UsageInfo; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.HashMap; @@ -913,6 +914,24 @@ public class RefactoringUtil { return array; } + @Nullable + public static PsiMethod getChainedConstructor(PsiMethod constructor) { + final PsiCodeBlock constructorBody = constructor.getBody(); + LOG.assertTrue(constructorBody != null); + final PsiStatement[] statements = constructorBody.getStatements(); + if (statements.length == 1 && statements[0] instanceof PsiExpressionStatement) { + final PsiExpression expression = ((PsiExpressionStatement)statements[0]).getExpression(); + if (expression instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; + final PsiReferenceExpression methodExpr = methodCallExpression.getMethodExpression(); + if ("this".equals(methodExpr.getReferenceName())) { + return (PsiMethod)methodExpr.resolve(); + } + } + } + return null; + } + public static interface ImplicitConstructorUsageVisitor { void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createConstructorParameterFromField/afterChainedCalls.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createConstructorParameterFromField/afterChainedCalls.java new file mode 100644 index 000000000000..830383e3a2ee --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createConstructorParameterFromField/afterChainedCalls.java @@ -0,0 +1,14 @@ +// "Add constructor parameter" "true" +class A { + private final int field; + private int j; + + A(int field) { + this(0, field); + } + + A(int j, int field) { + this.j = j; + this.field = field; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createConstructorParameterFromField/beforeChainedCalls.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createConstructorParameterFromField/beforeChainedCalls.java new file mode 100644 index 000000000000..5b1f93172630 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createConstructorParameterFromField/beforeChainedCalls.java @@ -0,0 +1,13 @@ +// "Add constructor parameter" "true" +class A { + private final int field; + private int j; + + A() { + this(0); + } + + A(int j) { + this.j = j; + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java index d9909974b33f..e00a6fe5cb99 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java @@ -64,6 +64,8 @@ import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.net.URL; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; class RunConfigurable extends BaseConfigurable { private static final Icon ICON = IconLoader.getIcon("/general/configurableRunDebug.png"); @@ -646,8 +648,8 @@ class RunConfigurable extends BaseConfigurable { } } - private static String createUniqueName(DefaultMutableTreeNode typeNode) { - String str = ExecutionBundle.message("run.configuration.unnamed.name.prefix"); + private static String createUniqueName(DefaultMutableTreeNode typeNode, @Nullable String baseName) { + String str = (baseName == null) ? ExecutionBundle.message("run.configuration.unnamed.name.prefix") : baseName; final ArrayList currentNames = new ArrayList(); for (int i = 0; i < typeNode.getChildCount(); i++) { final Object userObject = ((DefaultMutableTreeNode)typeNode.getChildAt(i)).getUserObject(); @@ -659,9 +661,13 @@ class RunConfigurable extends BaseConfigurable { } } if (!currentNames.contains(str)) return str; + + final Matcher matcher = Pattern.compile("(.*?)\\s*\\(\\d+\\)").matcher(str); + final String originalName = (matcher.matches()) ? matcher.group(1) : str; int i = 1; while (true) { - if (!currentNames.contains(str + i)) return str + i; + final String newName = String.format("%s (%d)", originalName, i); + if (!currentNames.contains(newName)) return newName; i++; } } @@ -692,7 +698,7 @@ class RunConfigurable extends BaseConfigurable { sortTree(myRoot); ((DefaultTreeModel)myTree.getModel()).reload(); } - final RunnerAndConfigurationSettings settings = getRunManager().createConfiguration(createUniqueName(node), factory); + final RunnerAndConfigurationSettings settings = getRunManager().createConfiguration(createUniqueName(node, null), factory); if (factory instanceof ConfigurationFactoryEx) { ((ConfigurationFactoryEx)factory).onNewConfigurationCreated(settings.getConfiguration()); } @@ -901,7 +907,7 @@ class RunConfigurable extends BaseConfigurable { try { final DefaultMutableTreeNode typeNode = getSelectedConfigurationTypeNode(); final RunnerAndConfigurationSettings settings = configuration.getSnapshot(); - final String copyName = createUniqueName(typeNode); + final String copyName = createUniqueName(typeNode, configuration.getNameText()); settings.setName(copyName); final ConfigurationFactory factory = settings.getFactory(); if (factory instanceof ConfigurationFactoryEx) { diff --git a/platform/platform-impl/src/com/intellij/ide/impl/ProjectUtil.java b/platform/platform-impl/src/com/intellij/ide/impl/ProjectUtil.java index 9a3dd2a4c89a..d164f33a7464 100644 --- a/platform/platform-impl/src/com/intellij/ide/impl/ProjectUtil.java +++ b/platform/platform-impl/src/com/intellij/ide/impl/ProjectUtil.java @@ -112,6 +112,14 @@ public class ProjectUtil { virtualFile.isDirectory() && virtualFile.findChild(DIRECTORY_BASED_PROJECT_DIR) != null) { return openProject(path, projectToClose, forceOpenInNewFrame); } + if (virtualFile.isDirectory()) { + for (VirtualFile child : virtualFile.getChildren()) { + final String childPath = child.getPath(); + if (childPath.endsWith(ProjectFileType.DOT_DEFAULT_EXTENSION)) { + return openProject(childPath, projectToClose, forceOpenInNewFrame); + } + } + } ProjectOpenProcessor provider = ProjectOpenProcessor.getImportProvider(virtualFile); if (provider != null) { return provider.doOpenProject(virtualFile, projectToClose, forceOpenInNewFrame); diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 99c8b10ffd4d..72747aca1c59 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -148,8 +148,8 @@ public class ContainerUtil { return hashMap; } - public static HashMap> classify(Iterator iterator, Convertor keyConvertor) { - HashMap> hashMap = new HashMap>(); + public static Map> classify(Iterator iterator, Convertor keyConvertor) { + Map> hashMap = new LinkedHashMap>(); while (iterator.hasNext()) { V value = iterator.next(); final K key = keyConvertor.convert(value); diff --git a/platform/util/testSrc/com/intellij/util/containers/WeaksTestCase.java b/platform/util/testSrc/com/intellij/util/containers/WeaksTestCase.java index 6f426d0e7a16..fb11d803bc07 100644 --- a/platform/util/testSrc/com/intellij/util/containers/WeaksTestCase.java +++ b/platform/util/testSrc/com/intellij/util/containers/WeaksTestCase.java @@ -47,7 +47,7 @@ public abstract class WeaksTestCase extends TestCase { System.gc(); try { List list = new ArrayList(); - while (Runtime.getRuntime().freeMemory() > 10000) { + while (Runtime.getRuntime().freeMemory() > 100000) { list.add(new byte[1000]); } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/quickedit/QuickEditAction.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/quickedit/QuickEditAction.java index 5fb44b4e2647..c94135fc6765 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/quickedit/QuickEditAction.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/quickedit/QuickEditAction.java @@ -45,6 +45,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.impl.source.resolve.FileContextUtil; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.impl.source.tree.injected.Place; @@ -292,7 +293,12 @@ public class QuickEditAction implements IntentionAction { new WriteCommandAction.Simple(myProject, origFile) { @Override protected void run() throws Throwable { - commitToOriginalInner(); + PostprocessReformattingAspect.getInstance(myProject).disablePostprocessFormattingInside(new Runnable() { + @Override + public void run() { + commitToOriginalInner(); + } + }); } }.execute(); } @@ -307,11 +313,14 @@ public class QuickEditAction implements IntentionAction { .classify(myMarkers.entrySet().iterator(), new Convertor>, PsiLanguageInjectionHost>() { public PsiLanguageInjectionHost convert(final Map.Entry> o) { - return (PsiLanguageInjectionHost)o.getKey().getElement(); + final PsiElement element = o.getKey().getElement(); + return (PsiLanguageInjectionHost)element; } }); PsiDocumentManager.getInstance(myProject).commitDocument(myOrigDocument); + int localInsideFileCursor = 0; for (PsiLanguageInjectionHost host : map.keySet()) { + if (host == null) continue; final String hostText = host.getText(); TextRange insideHost = null; final StringBuilder sb = new StringBuilder(); @@ -321,12 +330,13 @@ public class QuickEditAction implements IntentionAction { final TextRange localInsideHost = new TextRange(origMarker.getStartOffset() - hostOffset, origMarker.getEndOffset() - hostOffset); final RangeMarker rangeMarker = entry.getValue().second; - final TextRange localInsideFile = new TextRange(rangeMarker.getStartOffset(), rangeMarker.getEndOffset()); + final TextRange localInsideFile = new TextRange(Math.max(localInsideFileCursor, rangeMarker.getStartOffset()), rangeMarker.getEndOffset()); if (insideHost != null) { + //append unchanged inter-markers fragment sb.append(hostText.substring(insideHost.getEndOffset(), localInsideHost.getStartOffset())); } - sb.append(localInsideFile.getEndOffset() <= text.length()? localInsideFile.substring(text) : ""); - + sb.append(localInsideFile.getEndOffset() <= text.length() && !localInsideFile.isEmpty()? localInsideFile.substring(text) : ""); + localInsideFileCursor = localInsideFile.getEndOffset(); insideHost = insideHost == null ? localInsideHost : insideHost.union(localInsideHost); } assert insideHost != null; diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java index 378b10489558..87b73448c419 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java @@ -145,7 +145,7 @@ public class XmlAttributeInjection extends AbstractTagInjection { if (StringUtil.isNotEmpty(name)) appendStringPattern(result, ".withLocalName(", name, ")"); if (StringUtil.isNotEmpty(namespace)) appendStringPattern(result, ".withNamespace(", namespace, ")"); if (StringUtil.isNotEmpty(injection.getTagName()) || StringUtil.isNotEmpty(injection.getTagNamespace())) { - result.append(".inside(").append(XmlTagInjection.getPatternString(injection)).append(")"); + result.append(".withParent(").append(XmlTagInjection.getPatternString(injection)).append(")"); } return result.toString(); } diff --git a/plugins/IntelliLang/xml-support/resources/xmlInjections.xml b/plugins/IntelliLang/xml-support/resources/xmlInjections.xml index a965c7a303f0..f411b6c80a7c 100644 --- a/plugins/IntelliLang/xml-support/resources/xmlInjections.xml +++ b/plugins/IntelliLang/xml-support/resources/xmlInjections.xml @@ -7,16 +7,16 @@ JAXB attribute node - + */@href ^javascript:(.+) - + */@on.* - + */@style diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java index 0ebb8448b4db..64ba6c939cad 100644 --- a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java +++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java @@ -44,18 +44,17 @@ public class GppTypeConverter extends GrTypeConverter { @Override public Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context) { if (rType instanceof GrTupleType) { - final PsiType type = PsiUtil.extractIterableTypeParameter(lType, false); - if (type == null || TypesUtil.isAssignable(type, ((GrTupleType)rType).getParameters()[0], context)) { - final PsiType[] componentTypes = ((GrTupleType)rType).getComponentTypes(); + final GrTupleType tupleType = (GrTupleType)rType; - final PsiType expectedComponent = PsiUtil.extractIterableTypeParameter(lType, false); - if (expectedComponent != null && hasDefaultConstructor(lType)) { - return true; - } + final PsiType expectedComponent = PsiUtil.extractIterableTypeParameter(lType, false); + if (expectedComponent != null && + isMethodCallConversion(context) && TypesUtil.isAssignable(expectedComponent, tupleType.getParameters()[0], context) && + hasDefaultConstructor(lType)) { + return true; + } - if (lType instanceof PsiClassType && hasConstructor((PsiClassType)lType, componentTypes, context)) { - return true; - } + if (lType instanceof PsiClassType && hasConstructor((PsiClassType)lType, tupleType.getComponentTypes(), context)) { + return true; } } else if (rType instanceof GrMapType) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/ExcludeFromStubGenerationAction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/ExcludeFromStubGenerationAction.java index 1283d3152988..1933fabf3281 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/ExcludeFromStubGenerationAction.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/ExcludeFromStubGenerationAction.java @@ -36,6 +36,11 @@ public class ExcludeFromStubGenerationAction extends AnAction implements DumbAwa final PsiFile file = e.getData(DataKeys.PSI_FILE); assert file != null && file.getLanguage() == GroovyFileType.GROOVY_LANGUAGE; + + doExcludeFromStubGeneration(file); + } + + public static void doExcludeFromStubGeneration(PsiFile file) { final VirtualFile virtualFile = file.getVirtualFile(); assert virtualFile != null; final Project project = file.getProject(); @@ -46,7 +51,6 @@ public class ExcludeFromStubGenerationAction extends AnAction implements DumbAwa configurable.getExcludes().addEntry(new ExcludeEntryDescription(virtualFile, false, true, project)); } }); - } public void update(AnActionEvent e) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerLoader.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerLoader.java index 11f5e50feba6..a8ab5ded516e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerLoader.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerLoader.java @@ -17,9 +17,16 @@ package org.jetbrains.plugins.groovy.compiler; import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.components.AbstractProjectComponent; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.FileEditorManagerAdapter; +import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiClass; +import com.intellij.ui.EditorNotificationPanel; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.compiler.generator.GroovycStubGenerator; @@ -47,6 +54,47 @@ public class GroovyCompilerLoader extends AbstractProjectComponent { compilerManager.addTranslatingCompiler(new GroovyCompiler(myProject), new HashSet(Arrays.asList(GroovyFileType.GROOVY_FILE_TYPE, StdFileTypes.CLASS)), new HashSet(Arrays.asList(StdFileTypes.CLASS))); + + myProject.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() { + @Override + public void fileOpened(FileEditorManager source, final VirtualFile file) { + if (file.getName().endsWith(".java") && file.getPath().contains(GroovycStubGenerator.GROOVY_STUBS)) { + final PsiClass psiClass = GroovycStubGenerator.findClassByStub(myProject, file); + if (psiClass != null) { + final FileEditorManager fileEditorManager = FileEditorManager.getInstance(myProject); + final FileEditor[] editors = fileEditorManager.getEditors(file); + if (editors.length != 0) { + decorateStubFile(file, fileEditorManager, editors[0]); + } + + } + } + } + }); + } + + private void decorateStubFile(final VirtualFile file, FileEditorManager fileEditorManager, FileEditor editor) { + final EditorNotificationPanel panel = new EditorNotificationPanel(); + panel.setText("This stub is generated for Groovy class to make Groovy-Java cross-compilation possible"); + panel.createActionLabel("Go to the Groovy class", new Runnable() { + @Override + public void run() { + final PsiClass original = GroovycStubGenerator.findClassByStub(myProject, file); + if (original != null) { + original.navigate(true); + } + } + }); + panel.createActionLabel("Exclude from stub generation", new Runnable() { + @Override + public void run() { + final PsiClass psiClass = GroovycStubGenerator.findClassByStub(myProject, file); + if (psiClass != null) { + ExcludeFromStubGenerationAction.doExcludeFromStubGeneration(psiClass.getContainingFile()); + } + } + }); + fileEditorManager.addTopComponent(editor, panel); } @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java index 919e1431f0e8..8c00ad89a52d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.groovy.compiler.generator; +import com.intellij.codeInsight.generation.OverrideImplementUtil; import com.intellij.compiler.CompilerConfiguration; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.CompileContext; @@ -33,7 +34,9 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightMethodBuilder; import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; import com.intellij.psi.util.MethodSignatureUtil; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.CollectionFactory; import com.intellij.util.containers.ContainerUtil; @@ -43,6 +46,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.compiler.GroovyCompilerConfiguration; +import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; @@ -269,7 +273,7 @@ public class GroovyToJavaGenerator { } for (final GrTypeDefinition typeDefinition : file.getTypeDefinitions()) { - generatedItemsRelativePaths.add(createJavaSourceFile(outputRootDirectory, typeDefinition, packageDefinition)); + generatedItemsRelativePaths.add(createJavaSourceFile(outputRootDirectory, GrClassSubstitutor.getSubstitutedClass(typeDefinition), packageDefinition)); } return generatedItemsRelativePaths; @@ -351,20 +355,16 @@ public class GroovyToJavaGenerator { writePackageStatement(text, packageDefinition); - GrMembersDeclaration[] membersDeclarations = typeDefinition instanceof GrTypeDefinition - ? ((GrTypeDefinition)typeDefinition).getMemberDeclarations() - : GrMembersDeclaration.EMPTY_ARRAY; //todo - - boolean isClassDef = typeDefinition instanceof GrClassDefinition; - boolean isInterface = typeDefinition instanceof GrInterfaceDefinition; - boolean isEnum = typeDefinition instanceof GrEnumTypeDefinition; - boolean isAtInterface = typeDefinition instanceof GrAnnotationTypeDefinition; + boolean isEnum = typeDefinition.isEnum(); + boolean isAnnotationType = typeDefinition.isAnnotationType(); + boolean isInterface = !isAnnotationType && typeDefinition.isInterface(); + boolean isClassDef = !isInterface && !isEnum && !isAnnotationType && !isScript; writeClassModifiers(text, typeDefinition.getModifierList(), typeDefinition.isInterface(), toplevel); if (isInterface) text.append("interface"); else if (isEnum) text.append("enum"); - else if (isAtInterface) text.append("@interface"); + else if (isAnnotationType) text.append("@interface"); else text.append("class"); text.append(" ").append(typeDefinition.getName()); @@ -376,7 +376,7 @@ public class GroovyToJavaGenerator { if (isScript) { text.append("extends groovy.lang.Script "); } - else if (!isEnum && !isAtInterface) { + else if (!isEnum && !isAnnotationType) { final PsiClassType[] extendsClassesTypes = typeDefinition.getExtendsListTypes(); if (extendsClassesTypes.length > 0) { @@ -401,28 +401,32 @@ public class GroovyToJavaGenerator { writeEnumConstants(text, (GrEnumTypeDefinition)typeDefinition); } - Set methodSignatures = new HashSet(); + writeAllMethods(text, collectMethods(typeDefinition, isClassDef), typeDefinition); - - List methods = new ArrayList(); - ContainerUtil.addAll(methods, typeDefinition.getMethods()); - if (isClassDef) { - final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); - methods.add(factory.createMethodFromText("public groovy.lang.MetaClass getMetaClass() {}", null)); - methods.add(factory.createMethodFromText("public void setMetaClass(groovy.lang.MetaClass mc) {}", null)); - methods.add(factory.createMethodFromText("public Object invokeMethod(String name, Object args) {}", null)); - methods.add(factory.createMethodFromText("public Object getProperty(String propertyName) {}", null)); - methods.add(factory.createMethodFromText("public void setProperty(String propertyName, Object newValue) {}", null)); + if (typeDefinition instanceof GrTypeDefinition) { + for (GrMembersDeclaration declaration : ((GrTypeDefinition)typeDefinition).getMemberDeclarations()) { + if (declaration instanceof GrVariableDeclaration) { + writeVariableDeclarations(text, (GrVariableDeclaration)declaration); + } + } + } + for (PsiClass inner : typeDefinition.getInnerClasses()) { + writeTypeDefinition(text, inner, null, false); + text.append("\n"); } + text.append("}"); + } + private static void writeAllMethods(StringBuffer text, List methods, PsiClass aClass) { + Set methodSignatures = new HashSet(); for (PsiMethod method : methods) { if (LightMethodBuilder.isLightMethod(method, GrClassImplUtil.SYNTHETIC_METHOD_IMPLEMENTATION)) { continue; } if (method instanceof GrConstructor) { - writeConstructor(text, (GrConstructor)method, isEnum); + writeConstructor(text, (GrConstructor)method, aClass.isEnum()); continue; } @@ -455,18 +459,51 @@ public class GroovyToJavaGenerator { } } } + } - for (GrMembersDeclaration declaration : membersDeclarations) { - if (declaration instanceof GrVariableDeclaration) { - writeVariableDeclarations(text, (GrVariableDeclaration)declaration); + private List collectMethods(PsiClass typeDefinition, boolean classDef) { + List methods = new ArrayList(); + ContainerUtil.addAll(methods, typeDefinition.getMethods()); + if (classDef) { + final Collection toOverride = OverrideImplementUtil.getMethodSignaturesToOverride(typeDefinition); + for (MethodSignature signature : toOverride) { + if (signature instanceof MethodSignatureBackedByPsiMethod) { + final PsiMethod method = ((MethodSignatureBackedByPsiMethod)signature).getMethod(); + final PsiClass baseClass = method.getContainingClass(); + if (isAbstractInJava(method) && baseClass != null && typeDefinition.isInheritor(baseClass, true)) { + final LightMethodBuilder builder = new LightMethodBuilder(method.getManager(), method.getName()); + final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, typeDefinition, PsiSubstitutor.EMPTY); + for (PsiParameter parameter : method.getParameterList().getParameters()) { + builder.addParameter(parameter.getName(), substitutor.substitute(parameter.getType())); + } + builder.setReturnType(substitutor.substitute(method.getReturnType())); + for (String modifier : JAVA_MODIFIERS) { + if (method.hasModifierProperty(modifier)) { + builder.addModifier(modifier); + } + } + methods.add(builder); + } + } } + + final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); + methods.add(factory.createMethodFromText("public groovy.lang.MetaClass getMetaClass() {}", null)); + methods.add(factory.createMethodFromText("public void setMetaClass(groovy.lang.MetaClass mc) {}", null)); + methods.add(factory.createMethodFromText("public Object invokeMethod(String name, Object args) {}", null)); + methods.add(factory.createMethodFromText("public Object getProperty(String propertyName) {}", null)); + methods.add(factory.createMethodFromText("public void setProperty(String propertyName, Object newValue) {}", null)); } - for (PsiClass inner : typeDefinition.getInnerClasses()) { - writeTypeDefinition(text, inner, null, false); - text.append("\n"); + return methods; + } + + private static boolean isAbstractInJava(PsiMethod method) { + if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + return true; } - text.append("}"); + final PsiClass psiClass = method.getContainingClass(); + return psiClass != null && GrClassSubstitutor.getSubstitutedClass(psiClass).isInterface(); } private static void appendTypeParameters(StringBuffer text, PsiTypeParameterListOwner typeParameterListOwner) { @@ -670,7 +707,7 @@ public class GroovyToJavaGenerator { if (!JavaPsiFacade.getInstance(method.getProject()).getNameHelper().isIdentifier(name)) return; //does not have a java image - boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); + boolean isAbstract = isAbstractInJava(method); PsiModifierList modifierList = method.getModifierList(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java index 610e90131851..b0c87fa0078c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java @@ -26,13 +26,19 @@ import com.intellij.openapi.compiler.ex.CompileContextEx; import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.Chunk; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.compiler.GroovyCompilerBase; import org.jetbrains.plugins.groovy.compiler.GroovyCompilerConfiguration; @@ -40,6 +46,7 @@ import org.jetbrains.plugins.groovy.compiler.GroovyCompilerConfiguration; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -47,6 +54,8 @@ import java.util.List; */ public class GroovycStubGenerator extends GroovyCompilerBase { + public static final String GROOVY_STUBS = "groovyStubs"; + public GroovycStubGenerator(Project project) { super(project); } @@ -93,8 +102,7 @@ public class GroovycStubGenerator extends GroovyCompilerBase { @Override protected void compileFiles(CompileContext compileContext, Module module, final List toCompile, OutputSink sink, boolean tests) { - final String rootPath = CompilerPaths.getGeneratedDataDirectory(myProject) + "/groovyStubs/"; - final File outDir = new File(rootPath + myProject.getLocationHash() + "/" + module.getName() + "/" + (tests ? "tests" : "production") + "/"); + final File outDir = getStubOutput(module, tests); outDir.mkdirs(); final VirtualFile tempOutput = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(outDir); @@ -119,6 +127,26 @@ public class GroovycStubGenerator extends GroovyCompilerBase { } } + private static File getStubOutput(Module module, boolean tests) { + final Project project = module.getProject(); + final String rootPath = CompilerPaths.getGeneratedDataDirectory(project).getPath() + "/" + GROOVY_STUBS + "/"; + return new File(rootPath + project.getLocationHash() + "/" + module.getName() + "/" + (tests ? "tests" : "production") + "/"); + } + + @Nullable + public static PsiClass findClassByStub(Project project, VirtualFile stubFile) { + final String[] components = StringUtil.trimEnd(stubFile.getPath(), ".java").split("[\\\\/]"); + final int stubs = Arrays.asList(components).indexOf(GROOVY_STUBS); + if (stubs < 0 || stubs >= components.length - 4) return null; + + final String moduleName = components[stubs + 2]; + final Module module = ModuleManager.getInstance(project).findModuleByName(moduleName); + if (module == null) return null; + + final String fqn = StringUtil.join(Arrays.asList(components).subList(stubs + 4, components.length), "."); + return JavaPsiFacade.getInstance(project).findClass(fqn, GlobalSearchScope.moduleScope(module)); + } + private void cleanDirectory(final VirtualFile dir) { new WriteCommandAction(myProject) { protected void run(Result result) throws Throwable { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index 6b32b8c7ac69..639b59d79656 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -261,7 +261,7 @@ public class GroovyCompletionContributor extends CompletionContributor { } else if (call instanceof GrCallExpression) { GrCallExpression constructorCall = (GrCallExpression)call; - ContainerUtil.addAll(results, constructorCall.getMethodVariants()); + ContainerUtil.addAll(results, constructorCall.getMethodVariants(null)); final PsiType type = ((GrCallExpression)call).getType(); if (type instanceof PsiClassType) { final PsiClass psiClass = ((PsiClassType)type).resolve(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java index 3fdc0239b076..4f3b20e1ed4f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java @@ -5,6 +5,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; /** * @author peter @@ -12,7 +13,11 @@ import org.jetbrains.annotations.Nullable; public abstract class GrTypeConverter { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("org.intellij.groovy.typeConverter"); + protected static boolean isMethodCallConversion(GroovyPsiElement context) { + return context.getParent() instanceof GrMethodCall; + } + @Nullable public abstract Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context); -} \ No newline at end of file +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/path/GrCallExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/path/GrCallExpression.java index 84cf9d13c549..48aeb07117d5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/path/GrCallExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/path/GrCallExpression.java @@ -43,7 +43,7 @@ public interface GrCallExpression extends GrExpression, GrCall { PsiMethod resolveMethod(); @NotNull - GroovyResolveResult[] getMethodVariants(); + GroovyResolveResult[] getMethodVariants(@Nullable GrExpression upToArgument); //PsiElement addNamedArgument(GrNamedArgument argument); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java index a382c23d87e6..a37a96beddbd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java @@ -127,7 +127,7 @@ public class GroovyExpectedTypesProvider { final int closureIndex = closureArgs.indexOf(myExpression); if (closureIndex >= 0) { List constraints = new ArrayList(); - for (GroovyResolveResult variant : methodCall.getMethodVariants()) { + for (GroovyResolveResult variant : ResolveUtil.getMethodVariants(myExpression)) { PsiParameter[] parameters = getCallParameters(variant); if (parameters == null || parameters.length == 0) continue; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrContainerTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrContainerTypeConverter.java index 2fd193c1203a..a243ff54012b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrContainerTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrContainerTypeConverter.java @@ -32,6 +32,10 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt public class GrContainerTypeConverter extends GrTypeConverter { @Override public Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context) { + if (isMethodCallConversion(context)) { + return null; + } + if (!isCollectionOrArray(lType) || !isCollectionOrArray(rType)) return null; final PsiType lComponentType = extractComponentType(lType); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java index 7f0c4391bbf4..2a45e985ae61 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java @@ -115,7 +115,9 @@ public class GrMapType extends GrLiteralClassType { for (Pair entry : myOtherEntries) { components.add(getInternalCanonicalText(entry.first) + ":" + getInternalCanonicalText(entry.second)); } - return "[" + StringUtil.join(components, ", ") + "]"; + boolean tooMany = components.size() > 2; + final List theFirst = components.subList(0, Math.min(2, components.size())); + return "[" + StringUtil.join(theFirst, ", ") + (tooMany ? ",..." : "") + "]"; } public boolean isValid() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java index 13fc908f461e..8dd75907f1ad 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java @@ -59,6 +59,11 @@ public class GrTupleType extends GrLiteralClassType { StringBuilder builder = new StringBuilder(); builder.append("["); for (int i = 0; i < myComponentTypes.length; i++) { + if (i >= 2) { + builder.append(",..."); + break; + } + if (i > 0) builder.append(", "); builder.append(getInternalCanonicalText(myComponentTypes[i])); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java index d3726e2b1077..b79ecbde0668 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java @@ -42,7 +42,6 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -183,7 +182,7 @@ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewEx } @NotNull - public GroovyResolveResult[] getMethodVariants() { + public GroovyResolveResult[] getMethodVariants(@Nullable GrExpression upToArgument) { final GrCodeReferenceElement referenceElement = getReferenceElement(); if (referenceElement == null) return GroovyResolveResult.EMPTY_ARRAY; final GroovyResolveResult[] classResults = referenceElement.multiResolve(false); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index b62e74f3c2af..16311308b982 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -28,7 +28,10 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Consumer; +import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -61,7 +64,6 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.*; import java.util.ArrayList; -import java.util.Arrays; import java.util.EnumSet; import java.util.List; @@ -413,7 +415,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements Kind kind = refExpr.getKind(); if (incompleteCode) { ResolverProcessor processor = CompletionProcessor.createRefSameNameProcessor(refExpr, name); - resolveImpl(refExpr, processor); + refExpr.resolveImpl(processor); GroovyResolveResult[] propertyCandidates = processor.getCandidates(); if (propertyCandidates.length > 0) return propertyCandidates; } @@ -436,7 +438,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements GroovyResolveResult[] classCandidates = GroovyResolveResult.EMPTY_ARRAY; if (!hasAt) { ResolverProcessor classProcessor = new ClassResolverProcessor(refExpr.getReferenceName(), refExpr, kinds); - resolveImpl(refExpr, classProcessor); + refExpr.resolveImpl(classProcessor); classCandidates = classProcessor.getCandidates(); for (GroovyResolveResult classCandidate : classCandidates) { final PsiElement element = classCandidate.getElement(); @@ -447,7 +449,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements } ResolverProcessor processor = new PropertyResolverProcessor(name, refExpr); - resolveImpl(refExpr, processor); + refExpr.resolveImpl(processor); final GroovyResolveResult[] fieldCandidates = processor.getCandidates(); if (refExpr.hasAt()) { @@ -471,7 +473,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements List accessorResults = new ArrayList(); for (String getterName : names) { AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(getterName, refExpr, !isLValue); - resolveImpl(refExpr, accessorResolver); + refExpr.resolveImpl(accessorResolver); final GroovyResolveResult[] candidates = accessorResolver.getCandidates(); //can be only one candidate if (candidates.length == 1 && candidates[0].isStaticsOK()) { return candidates; @@ -488,18 +490,15 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements private static GroovyResolveResult[] resolveMethodOrProperty(GrReferenceExpressionImpl refExpr, String name) { final PsiType[] argTypes = PsiUtil.getArgumentTypes(refExpr, false); - PsiType thisType = getThisType(refExpr); - - MethodResolverProcessor methodResolver = - new MethodResolverProcessor(name, refExpr, false, thisType, argTypes, refExpr.getTypeArguments()); - resolveImpl(refExpr, methodResolver); + MethodResolverProcessor methodResolver = refExpr.runMethodResolverProcessor(argTypes, false); + assert methodResolver != null; if (methodResolver.hasApplicableCandidates()) return methodResolver.getCandidates(); final String[] names = GroovyPropertyUtils.suggestGettersName(name); List list = new ArrayList(); for (String getterName : names) { AccessorResolverProcessor getterResolver = new AccessorResolverProcessor(getterName, refExpr, true); - resolveImpl(refExpr, getterResolver); + refExpr.resolveImpl(getterResolver); final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate if (candidates.length == 1 && candidates[0].isStaticsOK()) { refExpr.putUserData(IS_RESOLVED_TO_GETTER, true); @@ -511,7 +510,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements } PropertyResolverProcessor propertyResolver = new PropertyResolverProcessor(name, refExpr); - resolveImpl(refExpr, propertyResolver); + refExpr.resolveImpl(propertyResolver); if (propertyResolver.hasCandidates()) return propertyResolver.getCandidates(); if (methodResolver.hasCandidates()) { @@ -525,144 +524,158 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements return GroovyResolveResult.EMPTY_ARRAY; } + } - private static void resolveImpl(GrReferenceExpressionImpl refExpr, ResolverProcessor processor) { - GrExpression qualifier = refExpr.getQualifierExpression(); - if (qualifier == null) { - ResolveUtil.treeWalkUp(refExpr, processor, true); - if (!processor.hasCandidates()) { - qualifier = PsiImplUtil.getRuntimeQualifier(refExpr); - if (qualifier != null) { - processQualifier(refExpr, processor, qualifier); - } + private void resolveImpl(ResolverProcessor processor) { + GrExpression qualifier = getQualifierExpression(); + if (qualifier == null) { + ResolveUtil.treeWalkUp(this, processor, true); + if (!processor.hasCandidates()) { + qualifier = PsiImplUtil.getRuntimeQualifier(this); + if (qualifier != null) { + processQualifier(processor, qualifier); } + } + } else { + if (getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) { + processQualifier(processor, qualifier); } else { - if (refExpr.getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) { - processQualifier(refExpr, processor, qualifier); - } else { - processQualifierForSpreadDot(refExpr, processor, qualifier); - } - - if (qualifier instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)qualifier).getReferenceName())) { - processIfJavaLangClass(refExpr, processor, qualifier.getType()); - } else if (qualifier instanceof GrThisReferenceExpression) { - processIfJavaLangClass(refExpr, processor, qualifier.getType()); - } - } - } - - private static void processIfJavaLangClass(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, PsiType type) { - if (type instanceof PsiClassType) { - final PsiClass psiClass = ((PsiClassType)type).resolve(); - if (psiClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) { - final PsiType[] params = ((PsiClassType)type).getParameters(); - if (params.length == 1) { - processClassQualifierType(refExpr, processor, params[0]); - } - } - } - } - - private static void processQualifierForSpreadDot(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, GrExpression qualifier) { - PsiType qualifierType = qualifier.getType(); - if (qualifierType instanceof PsiClassType) { - PsiClassType.ClassResolveResult result = ((PsiClassType) qualifierType).resolveGenerics(); - PsiClass clazz = result.getElement(); - if (clazz != null) { - PsiClass listClass = ResolveUtil.findListClass(refExpr.getManager(), refExpr.getResolveScope()); - if (listClass != null && listClass.getTypeParameters().length == 1) { - PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(listClass, clazz, result.getSubstitutor()); - if (substitutor != null) { - PsiType componentType = substitutor.substitute(listClass.getTypeParameters()[0]); - if (componentType != null) { - processClassQualifierType(refExpr, processor, componentType); - } - } - } - } - } else if (qualifierType instanceof PsiArrayType) { - processClassQualifierType(refExpr, processor, ((PsiArrayType) qualifierType).getComponentType()); - } - } - - private static void processQualifier(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, GrExpression qualifier) { - PsiType qualifierType = qualifier.getType(); - if (qualifierType == null) { - if (qualifier instanceof GrReferenceExpression) { - PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); - if (resolved instanceof PsiPackage) { - if (!resolved.processDeclarations(processor, ResolveState.initial(), null, refExpr)) //noinspection UnnecessaryReturnStatement - return; - } - else { - qualifierType = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory() - .createTypeByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, refExpr.getResolveScope()); - processClassQualifierType(refExpr, processor, qualifierType); - } - } - } else { - if (qualifierType instanceof PsiIntersectionType) { - for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { - processClassQualifierType(refExpr, processor, conjunct); - } - } else { - processClassQualifierType(refExpr, processor, qualifierType); - if (qualifier instanceof GrReferenceExpression) { - PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); - if (resolved instanceof PsiClass) { //omitted .class - PsiClass javaLangClass = PsiUtil.getJavaLangClass(resolved, refExpr.getResolveScope()); - if (javaLangClass != null) { - ResolveState state = ResolveState.initial(); - PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters(); - PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY); - if (substitutor == null) substitutor = PsiSubstitutor.EMPTY; - if (typeParameters.length == 1) { - substitutor = substitutor.put(typeParameters[0], qualifierType); - state = state.put(PsiSubstitutor.KEY, substitutor); - } - if (!javaLangClass.processDeclarations(processor, state, null, refExpr)) return; - PsiType javaLangClassType = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory().createType(javaLangClass, substitutor); - ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr, false); - } - } - } - } - } - } - - private static void processClassQualifierType(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, PsiType qualifierType) { - Project project = refExpr.getProject(); - if (qualifierType instanceof PsiClassType) { - PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType) qualifierType).resolveGenerics(); - PsiClass qualifierClass = qualifierResult.getElement(); - if (qualifierClass != null) { - if (!qualifierClass.processDeclarations(processor, - ResolveState.initial().put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, refExpr)) - return; - } - if (!ResolveUtil.processCategoryMembers(refExpr, processor)) return; - } else if (qualifierType instanceof PsiArrayType) { - final GrTypeDefinition arrayClass = GroovyPsiManager.getInstance(project).getArrayClass(); - if (!arrayClass.processDeclarations(processor, ResolveState.initial(), null, refExpr)) return; - } else if (qualifierType instanceof PsiIntersectionType) { - for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { - processClassQualifierType(refExpr, processor, conjunct); - } - return; + processQualifierForSpreadDot(processor, qualifier); } - ResolveUtil.processNonCodeMethods(qualifierType, processor, refExpr, false); + if (qualifier instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)qualifier).getReferenceName())) { + processIfJavaLangClass(processor, qualifier.getType()); + } else if (qualifier instanceof GrThisReferenceExpression) { + processIfJavaLangClass(processor, qualifier.getType()); + } } } - private static PsiType getThisType(GrReferenceExpression refExpr) { - GrExpression qualifier = refExpr.getQualifierExpression(); + private void processIfJavaLangClass(ResolverProcessor processor, PsiType type) { + if (type instanceof PsiClassType) { + final PsiClass psiClass = ((PsiClassType)type).resolve(); + if (psiClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) { + final PsiType[] params = ((PsiClassType)type).getParameters(); + if (params.length == 1) { + processClassQualifierType(processor, params[0]); + } + } + } + } + + private void processQualifierForSpreadDot(ResolverProcessor processor, GrExpression qualifier) { + PsiType qualifierType = qualifier.getType(); + if (qualifierType instanceof PsiClassType) { + PsiClassType.ClassResolveResult result = ((PsiClassType) qualifierType).resolveGenerics(); + PsiClass clazz = result.getElement(); + if (clazz != null) { + PsiClass listClass = ResolveUtil.findListClass(getManager(), getResolveScope()); + if (listClass != null && listClass.getTypeParameters().length == 1) { + PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(listClass, clazz, result.getSubstitutor()); + if (substitutor != null) { + PsiType componentType = substitutor.substitute(listClass.getTypeParameters()[0]); + if (componentType != null) { + processClassQualifierType(processor, componentType); + } + } + } + } + } else if (qualifierType instanceof PsiArrayType) { + processClassQualifierType(processor, ((PsiArrayType) qualifierType).getComponentType()); + } + } + + private void processQualifier(ResolverProcessor processor, GrExpression qualifier) { + PsiType qualifierType = qualifier.getType(); + if (qualifierType == null) { + if (qualifier instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); + if (resolved instanceof PsiPackage) { + if (!resolved.processDeclarations(processor, ResolveState.initial(), null, this)) //noinspection UnnecessaryReturnStatement + return; + } + else { + qualifierType = JavaPsiFacade.getInstance(getProject()).getElementFactory() + .createTypeByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, getResolveScope()); + processClassQualifierType(processor, qualifierType); + } + } + } else { + if (qualifierType instanceof PsiIntersectionType) { + for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { + processClassQualifierType(processor, conjunct); + } + } else { + processClassQualifierType(processor, qualifierType); + if (qualifier instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); + if (resolved instanceof PsiClass) { //omitted .class + PsiClass javaLangClass = PsiUtil.getJavaLangClass(resolved, getResolveScope()); + if (javaLangClass != null) { + ResolveState state = ResolveState.initial(); + PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters(); + PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY); + if (substitutor == null) substitutor = PsiSubstitutor.EMPTY; + if (typeParameters.length == 1) { + substitutor = substitutor.put(typeParameters[0], qualifierType); + state = state.put(PsiSubstitutor.KEY, substitutor); + } + if (!javaLangClass.processDeclarations(processor, state, null, this)) return; + PsiType javaLangClassType = JavaPsiFacade.getInstance(getProject()).getElementFactory().createType(javaLangClass, substitutor); + ResolveUtil.processNonCodeMethods(javaLangClassType, processor, this, false); + } + } + } + } + } + } + + private void processClassQualifierType(ResolverProcessor processor, PsiType qualifierType) { + Project project = getProject(); + if (qualifierType instanceof PsiClassType) { + PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType) qualifierType).resolveGenerics(); + PsiClass qualifierClass = qualifierResult.getElement(); + if (qualifierClass != null) { + if (!qualifierClass.processDeclarations(processor, + ResolveState.initial().put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, this)) + return; + } + if (!ResolveUtil.processCategoryMembers(this, processor)) return; + } else if (qualifierType instanceof PsiArrayType) { + final GrTypeDefinition arrayClass = GroovyPsiManager.getInstance(project).getArrayClass(); + if (!arrayClass.processDeclarations(processor, ResolveState.initial(), null, this)) return; + } else if (qualifierType instanceof PsiIntersectionType) { + for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { + processClassQualifierType(processor, conjunct); + } + return; + } + + ResolveUtil.processNonCodeMethods(qualifierType, processor, this, false); + } + + @Nullable + public MethodResolverProcessor runMethodResolverProcessor(PsiType[] argTypes, final boolean allVariants) { + final String name = getReferenceName(); + if (name == null) { + return null; + } + + PsiType thisType = getThisType(); + + MethodResolverProcessor methodResolver = new MethodResolverProcessor(name, this, false, thisType, argTypes, getTypeArguments(), allVariants); + resolveImpl(methodResolver); + return methodResolver; + } + + private PsiType getThisType() { + GrExpression qualifier = getQualifierExpression(); if (qualifier != null) { PsiType qType = qualifier.getType(); if (qType != null) return qType; } - return TypesUtil.getJavaLangObject(refExpr); + return TypesUtil.getJavaLangObject(this); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index f3d736fb87bc..26a0d6868e64 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -233,6 +233,23 @@ public class TypesUtil { } public static boolean isAssignable(PsiType lType, PsiType rType, GroovyPsiElement context, boolean allowConversion) { + if (rType instanceof PsiIntersectionType) { + for (PsiType child : ((PsiIntersectionType)rType).getConjuncts()) { + if (isAssignable(lType, child, context, allowConversion)) { + return true; + } + } + return false; + } + if (lType instanceof PsiIntersectionType) { + for (PsiType child : ((PsiIntersectionType)lType).getConjuncts()) { + if (!isAssignable(child, rType, context, allowConversion)) { + return false; + } + } + return true; + } + if (allowConversion && lType != null && rType != null) { for (GrTypeConverter converter : GrTypeConverter.EP_NAME.getExtensions()) { final Boolean result = converter.isConvertible(lType, rType, context); @@ -267,7 +284,20 @@ public class TypesUtil { } public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, GroovyPsiElement context) { - return isAssignableByMethodCallConversion(lType, rType, context.getManager(), context.getResolveScope()); + if (lType == null || rType == null) return false; + + if (isAssignableByMethodCallConversion(lType, rType, context.getManager(), context.getResolveScope())) { + return true; + } + + for (GrTypeConverter converter : GrTypeConverter.EP_NAME.getExtensions()) { + final Boolean result = converter.isConvertible(lType, rType, context); + if (result != null) { + return result; + } + } + + return false; } public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, PsiManager manager, GlobalSearchScope scope) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrMethodCallExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrMethodCallExpressionImpl.java index 720b0dcc0cd0..5a7033e7aefc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrMethodCallExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrMethodCallExpressionImpl.java @@ -41,9 +41,9 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrRefer import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor; import java.util.ArrayList; -import java.util.Arrays; /** * @author ilyas @@ -187,21 +187,17 @@ public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements } @NotNull - public GroovyResolveResult[] getMethodVariants() { + public GroovyResolveResult[] getMethodVariants(@Nullable GrExpression upToArgument) { final GrExpression invoked = getInvokedExpression(); - if (!(invoked instanceof GrReferenceExpression)) return GroovyResolveResult.EMPTY_ARRAY; - final ArrayList res = new ArrayList(); + if (!(invoked instanceof GrReferenceExpressionImpl)) return GroovyResolveResult.EMPTY_ARRAY; - for (PsiReference ref : invoked.getReferences()) { - if (ref instanceof PsiPolyVariantReference) { - for (ResolveResult result : ((PsiPolyVariantReference)ref).multiResolve(true)) { - if (result instanceof GroovyResolveResult) { - res.add((GroovyResolveResult)result); - } - } - } + final PsiType[] partialArgs = PsiUtil.getArgumentTypes(invoked, false, upToArgument); + final MethodResolverProcessor processor = ((GrReferenceExpressionImpl)invoked).runMethodResolverProcessor(partialArgs, true); + if (processor != null) { + return processor.getCandidates(); } - return res.toArray(new GroovyResolveResult[res.size()]); + + return GroovyResolveResult.EMPTY_ARRAY; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyExpressionPattern.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyExpressionPattern.java index 2f6af4b020c7..67b76bf82b5b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyExpressionPattern.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyExpressionPattern.java @@ -42,7 +42,7 @@ public class GroovyExpressionPattern method) { return new GroovyMethodCallPattern().and(this).with(new PatternCondition("methodCall") { public boolean accepts(@NotNull GrCallExpression callExpression, ProcessingContext context) { - final GroovyResolveResult[] results = callExpression.getMethodVariants(); + final GroovyResolveResult[] results = callExpression.getMethodVariants(null); for (GroovyResolveResult result : results) { if (method.getCondition().accepts(result.getElement(), context)) { return true; @@ -72,4 +72,4 @@ public class GroovyExpressionPattern result = new ArrayList(); @@ -193,6 +197,9 @@ public class PsiUtil { } else { result.add(type); } + if (stopAt == expression) { + return result.toArray(new PsiType[result.size()]); + } } GrClosableBlock[] closures = call.getClosureArguments(); @@ -201,6 +208,9 @@ public class PsiUtil { if (closureType != null) { result.add(closureType); } + if (stopAt == closure) { + break; + } } return result.toArray(new PsiType[result.size()]); @@ -224,6 +234,9 @@ public class PsiUtil { } else { result.add(type); } + if (stopAt == expression) { + break; + } } return result.toArray(new PsiType[result.size()]); @@ -245,6 +258,10 @@ public class PsiUtil { else { result.add(argType); } + if (stopAt == arg) { + break; + } + } return result.toArray(new PsiType[result.size()]); } else if (parent instanceof GrConstructorInvocation || parent instanceof GrEnumConstant) { @@ -264,6 +281,10 @@ public class PsiUtil { } else { result.add(type); } + if (stopAt == expression) { + break; + } + } return result.toArray(new PsiType[result.size()]); @@ -603,7 +624,7 @@ public class PsiUtil { } public static boolean isRawMethodCall(GrMethodCallExpression call) { - final GroovyResolveResult[] resolveResults = call.getMethodVariants(); + final GroovyResolveResult[] resolveResults = call.getMethodVariants(null); if (resolveResults.length == 0) return false; final PsiElement element = resolveResults[0].getElement(); if (element instanceof PsiMethod) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index 080c3de1fe9f..49a3ed5858e7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -444,7 +444,7 @@ public class ResolveUtil { final PsiElement parent = place.getParent(); GroovyResolveResult[] variants = GroovyResolveResult.EMPTY_ARRAY; if (parent instanceof GrCallExpression) { - variants = ((GrCallExpression) parent).getMethodVariants(); + variants = ((GrCallExpression) parent).getMethodVariants(place instanceof GrExpression ? (GrExpression)place : null); } else if (parent instanceof GrConstructorInvocation) { final PsiClass clazz = ((GrConstructorInvocation) parent).getDelegatedClass(); if (clazz != null) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java index 901e599a4eef..3e225918b136 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java @@ -50,6 +50,7 @@ public class MethodResolverProcessor extends ResolverProcessor { @Nullable private final PsiType[] myArgumentTypes; private final PsiType[] myTypeArguments; + private final boolean myAllVariants; private final Set myInapplicableCandidates = new LinkedHashSet(); private final boolean myIsConstructor; @@ -57,11 +58,15 @@ public class MethodResolverProcessor extends ResolverProcessor { private boolean myStopExecuting = false; public MethodResolverProcessor(String name, GroovyPsiElement place, boolean isConstructor, PsiType thisType, @Nullable PsiType[] argumentTypes, PsiType[] typeArguments) { + this(name, place, isConstructor, thisType, argumentTypes, typeArguments, false); + } + public MethodResolverProcessor(String name, GroovyPsiElement place, boolean isConstructor, PsiType thisType, @Nullable PsiType[] argumentTypes, PsiType[] typeArguments, boolean allVariants) { super(name, EnumSet.of(ResolveKind.METHOD, ResolveKind.PROPERTY), place, PsiType.EMPTY_ARRAY); myIsConstructor = isConstructor; myThisType = thisType; myArgumentTypes = argumentTypes; myTypeArguments = typeArguments; + myAllVariants = allVariants; } public boolean execute(PsiElement element, ResolveState state) { @@ -78,7 +83,7 @@ public class MethodResolverProcessor extends ResolverProcessor { boolean isAccessible = isAccessible(method); GroovyPsiElement fileResolveContext = state.get(RESOLVE_CONTEXT); boolean isStaticsOK = isStaticsOK(method, fileResolveContext); - if (PsiUtil.isApplicable(myArgumentTypes, method, substitutor, fileResolveContext instanceof GrMethodCallExpression, (GroovyPsiElement)myPlace) && isStaticsOK) { + if (!myAllVariants && PsiUtil.isApplicable(myArgumentTypes, method, substitutor, fileResolveContext instanceof GrMethodCallExpression, (GroovyPsiElement)myPlace) && isStaticsOK) { myCandidates.add(new GroovyResolveResultImpl(method, fileResolveContext, substitutor, isAccessible, isStaticsOK)); } else { myInapplicableCandidates.add(new GroovyResolveResultImpl(method, fileResolveContext, substitutor, isAccessible, isStaticsOK)); @@ -213,6 +218,10 @@ public class MethodResolverProcessor extends ResolverProcessor { @NotNull public GroovyResolveResult[] getCandidates() { + if (myAllVariants) { + return myInapplicableCandidates.toArray(new GroovyResolveResult[myInapplicableCandidates.size()]); + } + if (!myCandidates.isEmpty()) { return filterCandidates(); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GppCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GppCompilerTest.groovy new file mode 100644 index 000000000000..3de2fac8e4ab --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GppCompilerTest.groovy @@ -0,0 +1,61 @@ +/* + * 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 org.jetbrains.plugins.groovy.compiler; + + +import com.intellij.testFramework.PsiTestUtil +import org.jetbrains.plugins.groovy.util.TestUtils + +/** + * @author peter + */ +public class GppCompilerTest extends GroovyCompilerTestCase { + @Override protected void setUp() { + super.setUp(); + PsiTestUtil.addLibrary myFixture.module, "gpp", TestUtils.absoluteTestDataPath + "/realGroovypp/", "groovypp-all-0.2.13.jar" + } + + public void testTraitStubs() throws Throwable { + myFixture.addFileToProject("A.groovy", """ +@Trait +abstract class SomeTrait { + abstract def some() + def concrete() {} +} + +@Trait +abstract class AnotherTrait extends SomeTrait { + abstract def another() +} + +class Goo implements SomeTrait { + def some() {} +} +class Bar implements AnotherTrait { + def some() {} + def another() {} +} +"""); + myFixture.addClass(""" +class Foo implements SomeTrait { + public Object some() { return null; } + public Object concrete() { return null; } +}""") + assertEmpty(make()); + } + +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy index a1165622bdaa..5fa105608aee 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy @@ -27,6 +27,10 @@ import junit.framework.AssertionFailedError * @author peter */ public class GroovyCompilerTest extends GroovyCompilerTestCase { + @Override protected void setUp() { + super.setUp(); + addGroovyLibrary(myModule, getName().contains("1_7")); + } public void testPlainGroovy() throws Throwable { myFixture.addFileToProject("A.groovy", "println '239'"); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java index 1ed0cf0d6444..2f695bf97438 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java @@ -71,8 +71,6 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC CompilerProjectExtension.getInstance(getProject()).setCompilerOutputUrl(myMainOutput.findOrCreateDir("out").getUrl()); } }.execute(); - - addGroovyLibrary(myModule, getName().contains("1_7")); } @Override diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy index 6c26a5010bc4..345efb7e3450 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy @@ -36,17 +36,17 @@ class GppFunctionalTest extends LightCodeInsightFixtureTestCase { super.setUp() } - public void _testCastListToIterable() throws Exception { + public void testCastListToIterable() throws Exception { myFixture.addClass("class X extends java.util.ArrayList {}") testAssignability """ X ints = [239, 4.2d] """ } - public void _testCastListToAnything() throws Exception { + public void testCastListToAnything() throws Exception { testAssignability """ File f1 = ['path'] -File f2 = ['path', 2, true, 42] +File f2 = ['path', 2, true, 42] """ } @@ -323,7 +323,7 @@ class BarImpl extends Bar {} return myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset).resolve() } - public void _testMethodTypeParameterInference() throws Exception { + public void testMethodTypeParameterInference() throws Exception { configureScript """ @Typed package aaa @@ -334,7 +334,7 @@ r.apply { it.intVi } assertSameElements myFixture.getLookupElementStrings(), "intValue" } - public void _testMethodTypeParameterInference2() throws Exception { + public void testMethodTypeParameterInference2() throws Exception { configureScript """ @Typed package aaa @@ -385,4 +385,4 @@ class GppProjectDescriptor extends DefaultLightProjectDescriptor { modifiableModel.addRoot(JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.mockGroovy1_7LibraryName + "!/"), OrderRootType.CLASSES); modifiableModel.commit(); } -} \ No newline at end of file +} diff --git a/plugins/groovy/testdata/highlighting/SignatureIsNotApplicableToList.groovy b/plugins/groovy/testdata/highlighting/SignatureIsNotApplicableToList.groovy index be1878b6974d..f0b8f175ba66 100644 --- a/plugins/groovy/testdata/highlighting/SignatureIsNotApplicableToList.groovy +++ b/plugins/groovy/testdata/highlighting/SignatureIsNotApplicableToList.groovy @@ -1,3 +1,3 @@ def foo(int... i) {} def list = [1, 2, 3] -foo(list) \ No newline at end of file +foo(list) \ No newline at end of file diff --git a/plugins/groovy/testdata/realGroovypp/groovypp-all-0.2.13.jar b/plugins/groovy/testdata/realGroovypp/groovypp-all-0.2.13.jar new file mode 100644 index 000000000000..38fb41b3cd1c Binary files /dev/null and b/plugins/groovy/testdata/realGroovypp/groovypp-all-0.2.13.jar differ diff --git a/plugins/junit/src/com/intellij/execution/junit2/inspection/JUnitUnusedCodeExtension.java b/plugins/junit/src/com/intellij/execution/junit2/inspection/JUnitUnusedCodeExtension.java index ae57f1e7d8e0..590e9f2ba0b1 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/inspection/JUnitUnusedCodeExtension.java +++ b/plugins/junit/src/com/intellij/execution/junit2/inspection/JUnitUnusedCodeExtension.java @@ -80,6 +80,8 @@ public class JUnitUnusedCodeExtension extends UnusedCodeExtension { } public void writeExternal(Element element) throws WriteExternalException { - DefaultJDOMExternalizer.writeExternal(this, element); + if (!ADD_JUNIT_TO_ENTRIES) { + DefaultJDOMExternalizer.writeExternal(this, element); + } } } \ No newline at end of file diff --git a/plugins/testng/src/com/theoryinpractice/testng/inspection/TestNGUnusedCodeExtension.java b/plugins/testng/src/com/theoryinpractice/testng/inspection/TestNGUnusedCodeExtension.java index b10c1633dd8b..51423d3f32bb 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/inspection/TestNGUnusedCodeExtension.java +++ b/plugins/testng/src/com/theoryinpractice/testng/inspection/TestNGUnusedCodeExtension.java @@ -68,7 +68,9 @@ public class TestNGUnusedCodeExtension extends UnusedCodeExtension { } public void writeExternal(Element element) throws WriteExternalException { - DefaultJDOMExternalizer.writeExternal(this, element); + if (!ADD_TESTNG_TO_ENTRIES) { + DefaultJDOMExternalizer.writeExternal(this, element); + } } @Nullable diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/ConvertSchemaPrefixToDefaultIntention.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/ConvertSchemaPrefixToDefaultIntention.java index ab8b909e8998..d524eb2c95bd 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/ConvertSchemaPrefixToDefaultIntention.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/ConvertSchemaPrefixToDefaultIntention.java @@ -86,7 +86,10 @@ public class ConvertSchemaPrefixToDefaultIntention extends PsiElementBaseIntenti protected void run(Result result) throws Throwable { final int index = ns.length() + 1; for (XmlTag tag : tags) { - tag.setName(tag.getName().substring(index)); + final String s = tag.getName().substring(index); + if (s.length() > 0) { + tag.setName(s); + } } for (XmlAttribute attr : attrs) { attr.setValue(attr.getValue().substring(index)); diff --git a/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java b/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java index 3e734d337b04..6c9e1c444782 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java +++ b/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java @@ -16,8 +16,10 @@ package com.intellij.psi.impl.source.resolve.reference.impl.manipulators; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; import com.intellij.psi.AbstractElementManipulator; +import com.intellij.psi.PsiElement; import com.intellij.psi.xml.XmlText; import com.intellij.util.IncorrectOperationException; @@ -27,14 +29,27 @@ import com.intellij.util.IncorrectOperationException; public class XmlTextManipulator extends AbstractElementManipulator { public XmlText handleContentChange(XmlText text, TextRange range, String newContent) throws IncorrectOperationException { - - final StringBuilder replacement = new StringBuilder(text.getValue()); - replacement.replace( - range.getStartOffset(), - range.getEndOffset(), - newContent - ); - text.setValue(replacement.toString()); + final String newValue; + final String value = text.getValue(); + if (range.equals(getRangeInElement(text))) { + newValue = newContent; + } + else { + final StringBuilder replacement = new StringBuilder(value); + replacement.replace( + range.getStartOffset(), + range.getEndOffset(), + newContent + ); + newValue = replacement.toString(); + } + if (Comparing.equal(value, newValue)) return text; + if (newValue.length() > 0) { + text.setValue(newValue); + } + else { + text.deleteChildRange(text.getFirstChild(), text.getLastChild()); + } return text; }