diff --git a/RegExpSupport/src/org/intellij/lang/regexp/DefaultRegExpPropertiesProvider.java b/RegExpSupport/src/org/intellij/lang/regexp/DefaultRegExpPropertiesProvider.java index 5c88ac26106c..b0e6e888a810 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/DefaultRegExpPropertiesProvider.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/DefaultRegExpPropertiesProvider.java @@ -4,7 +4,13 @@ import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -final class DefaultRegExpPropertiesProvider implements RegExpPropertiesProvider { +public final class DefaultRegExpPropertiesProvider { + private static final DefaultRegExpPropertiesProvider INSTANCE = new DefaultRegExpPropertiesProvider(); + + public static DefaultRegExpPropertiesProvider getInstance() { + return INSTANCE; + } + private final String[][] myPropertyNames = { { "Cn", "UNASSIGNED" }, { "Lu", "UPPERCASE_LETTER" }, @@ -98,10 +104,9 @@ final class DefaultRegExpPropertiesProvider implements RegExpPropertiesProvider {"e", "escape character ('\\u001B')"} }; - public DefaultRegExpPropertiesProvider() { + private DefaultRegExpPropertiesProvider() { } - @Override public boolean isValidCategory(@NotNull String category) { if (category.startsWith("In")) { try { @@ -121,7 +126,6 @@ final class DefaultRegExpPropertiesProvider implements RegExpPropertiesProvider return false; } - @Override @Nullable public String getPropertyDescription(@Nullable final String name) { if (StringUtil.isEmptyOrSpaces(name)) { @@ -135,14 +139,12 @@ final class DefaultRegExpPropertiesProvider implements RegExpPropertiesProvider return null; } - @Override @NotNull public String[][] getAllKnownProperties() { return myPropertyNames; } @NotNull - @Override public String[][] getKnownCharacterClasses() { return myCharacterClasses; } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java index 158f4a90534f..51f1bd83ba04 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java @@ -90,7 +90,7 @@ public final class RegExpCompletionContributor extends CompletionContributor { public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { - for (String[] stringArray : getProvider(parameters).getAllKnownProperties()) { + for (String[] stringArray : RegExpLanguageHosts.getInstance().getAllKnownProperties(parameters.getPosition())) { result.addElement( TailTypeDecorator.withTail(createLookupElement(stringArray[0], null, emptyIcon), TailType.createSimpleTailType('}'))); } @@ -102,7 +102,7 @@ public final class RegExpCompletionContributor extends CompletionContributor { public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { - for (String[] stringArray : getProvider(parameters).getAllKnownProperties()) { + for (String[] stringArray : RegExpLanguageHosts.getInstance().getAllKnownProperties(parameters.getPosition())) { addLookupElement(result, "{" + stringArray[0] + "}", stringArray.length > 1 ? stringArray[1]:null, PlatformIcons.PROPERTY_ICON); } } @@ -114,19 +114,13 @@ public final class RegExpCompletionContributor extends CompletionContributor { final ProcessingContext context, @NotNull final CompletionResultSet result) { - final RegExpPropertiesProvider provider = getProvider(parameters); - for (final String[] completion : provider.getKnownCharacterClasses()) { + for (final String[] completion : RegExpLanguageHosts.getInstance().getKnownCharacterClasses(parameters.getPosition())) { addLookupElement(result, completion[0], completion[1], emptyIcon); } - for (String[] stringArray : provider.getAllKnownProperties()) { + for (String[] stringArray : RegExpLanguageHosts.getInstance().getAllKnownProperties(parameters.getPosition())) { addLookupElement(result, "p{" + stringArray[0] + "}", stringArray.length > 1? stringArray[1]:null, PlatformIcons.PROPERTY_ICON); } } } - - @NotNull - private static RegExpPropertiesProvider getProvider(@NotNull final CompletionParameters parameters) { - return RegExpPropertiesProviders.getInstance().forLanguage(parameters.getOriginalFile().getLanguage()); - } } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpDocumentationProvider.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpDocumentationProvider.java index 86add8bd7658..7f1da1937ee4 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpDocumentationProvider.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpDocumentationProvider.java @@ -34,7 +34,7 @@ public final class RegExpDocumentationProvider extends AbstractDocumentationProv final RegExpProperty prop = (RegExpProperty)element; final ASTNode node = prop.getCategoryNode(); if (node != null) { - final String description = RegExpPropertiesProviders.forNode(node).getPropertyDescription(node.getText()); + final String description = RegExpLanguageHosts.getInstance().getPropertyDescription(node.getPsi(), node.getText()); if (description != null) { if (prop.isNegated()) { return "Property block stands for characters not matching " + description; diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHost.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHost.java index c283f19e87af..9208a3239fc3 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHost.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHost.java @@ -16,6 +16,8 @@ package org.intellij.lang.regexp; import org.intellij.lang.regexp.psi.RegExpGroup; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author yole @@ -26,4 +28,12 @@ public interface RegExpLanguageHost { boolean supportsPossessiveQuantifiers(); boolean supportsPythonConditionalRefs(); boolean supportsNamedGroupSyntax(RegExpGroup group); + + boolean isValidCategory(@NotNull String category); + @NotNull + String[][] getAllKnownProperties(); + @Nullable + String getPropertyDescription(@Nullable final String name); + @NotNull + String[][] getKnownCharacterClasses(); } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHosts.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHosts.java index d36e7e6a009c..636c97193d2a 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHosts.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHosts.java @@ -15,15 +15,110 @@ */ package org.intellij.lang.regexp; +import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.util.ClassExtension; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiLanguageInjectionHost; +import org.intellij.lang.regexp.psi.RegExpChar; +import org.intellij.lang.regexp.psi.RegExpGroup; +import org.intellij.lang.regexp.psi.RegExpPyCondRef; +import org.intellij.lang.regexp.psi.RegExpQuantifier; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author yole */ -public class RegExpLanguageHosts extends ClassExtension { - public static final RegExpLanguageHosts INSTANCE = new RegExpLanguageHosts(); +public final class RegExpLanguageHosts extends ClassExtension { + private static final RegExpLanguageHosts INSTANCE = new RegExpLanguageHosts(); + private final DefaultRegExpPropertiesProvider myDefaultProvider; + + public static RegExpLanguageHosts getInstance() { + return INSTANCE; + } private RegExpLanguageHosts() { super("com.intellij.regExpLanguageHost"); + myDefaultProvider = DefaultRegExpPropertiesProvider.getInstance(); + } + + @Nullable + private static RegExpLanguageHost findRegExpHost(@Nullable final PsiElement element) { + if (element == null) { + return null; + } + PsiLanguageInjectionHost host = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element); + if (host instanceof RegExpLanguageHost) { + return (RegExpLanguageHost)host; + } + if (host != null) { + return INSTANCE.forClass(host.getClass()); + } + return null; + } + + public boolean isRedundantEscape(@NotNull final RegExpChar ch, @NotNull final String text) { + if (text.length() <= 1) { + return false; + } + final RegExpLanguageHost host = findRegExpHost(ch); + if (host != null) { + final char c = text.charAt(1); + final boolean needsEscaping = host.characterNeedsEscaping(c); + return !needsEscaping; + } + else { + return !("\\]".equals(text) || "\\}".equals(text)); + } + } + + public boolean supportsNamedGroupSyntax(@Nullable final RegExpGroup group) { + final RegExpLanguageHost host = findRegExpHost(group); + return host != null && host.supportsNamedGroupSyntax(group); + } + + public boolean supportsPerl5EmbeddedComments(@Nullable final PsiComment comment) { + final RegExpLanguageHost host = findRegExpHost(comment); + return host != null && host.supportsPerl5EmbeddedComments(); + } + + public boolean supportsPythonConditionalRefs(@Nullable final RegExpPyCondRef condRef) { + final RegExpLanguageHost host = findRegExpHost(condRef); + return host != null && host.supportsPythonConditionalRefs(); + } + + public boolean supportsPossessiveQuantifiers(@Nullable final RegExpQuantifier quantifier) { + final RegExpLanguageHost host = findRegExpHost(quantifier); + return host != null && host.supportsPossessiveQuantifiers(); + } + + public boolean isValidCategory(@NotNull final PsiElement element, @NotNull String category) { + final RegExpLanguageHost host = findRegExpHost(element); + if (host == null) { + return false; + } + return host.isValidCategory(category); + } + + @NotNull + public String[][] getAllKnownProperties(@NotNull final PsiElement element) { + final RegExpLanguageHost host = findRegExpHost(element); + if (host != null) { + return host.getAllKnownProperties(); + } + return myDefaultProvider.getAllKnownProperties(); + } + + @Nullable + String getPropertyDescription(@NotNull final PsiElement element, @Nullable final String name) { + final RegExpLanguageHost host = findRegExpHost(element); + return host == null ? null : host.getPropertyDescription(name); + } + + @NotNull + String[][] getKnownCharacterClasses(@NotNull final PsiElement element) { + final RegExpLanguageHost host = findRegExpHost(element); + return host != null ? host.getKnownCharacterClasses() : myDefaultProvider.getKnownCharacterClasses(); } } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpPropertiesProvider.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpPropertiesProvider.java deleted file mode 100644 index 6c7bfac3d43d..000000000000 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpPropertiesProvider.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.intellij.lang.regexp; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public interface RegExpPropertiesProvider { - boolean isValidCategory(@NotNull String category); - - @Nullable - String getPropertyDescription(@Nullable final String name); - - @NotNull - String[][] getAllKnownProperties(); - - @NotNull - String[][] getKnownCharacterClasses(); -} diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpPropertiesProviders.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpPropertiesProviders.java deleted file mode 100644 index beb7804f5a87..000000000000 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpPropertiesProviders.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.intellij.lang.regexp; - -import com.intellij.lang.ASTNode; -import com.intellij.lang.LanguageExtension; -import org.jetbrains.annotations.NotNull; - -public final class RegExpPropertiesProviders extends LanguageExtension { - private static final RegExpPropertiesProviders INSTANCE = new RegExpPropertiesProviders(); - - public static RegExpPropertiesProviders getInstance() { - return INSTANCE; - } - - public RegExpPropertiesProviders() { - super("com.intellij.regExpPropertiesProvider", new DefaultRegExpPropertiesProvider()); - } - - public static RegExpPropertiesProvider forNode(@NotNull final ASTNode node) { - return getInstance().forLanguage(node.getPsi().getContainingFile().getLanguage()); - } -} diff --git a/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpPropertyImpl.java b/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpPropertyImpl.java index 42ddbebdf31e..5c97ac35489b 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpPropertyImpl.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpPropertyImpl.java @@ -25,7 +25,7 @@ import com.intellij.psi.PsiReference; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.PlatformIcons; -import org.intellij.lang.regexp.RegExpPropertiesProviders; +import org.intellij.lang.regexp.RegExpLanguageHosts; import org.intellij.lang.regexp.RegExpTT; import org.intellij.lang.regexp.psi.RegExpElementVisitor; import org.intellij.lang.regexp.psi.RegExpProperty; @@ -106,7 +106,7 @@ public class RegExpPropertyImpl extends RegExpElementImpl implements RegExpPrope if (categoryNode != null && categoryNode.getText().startsWith("In") && !categoryNode.getText().startsWith("Intelli")) { return UNICODE_BLOCKS; } else { - final String[][] knownProperties = RegExpPropertiesProviders.forNode(getNode()).getAllKnownProperties(); + final String[][] knownProperties = RegExpLanguageHosts.getInstance().getAllKnownProperties(getElement()); final Object[] objects = new Object[knownProperties.length]; for (int i = 0; i < objects.length; i++) { final String[] prop = knownProperties[i]; diff --git a/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java b/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java index 29626c69d04d..1d32bf8ab6eb 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java @@ -21,20 +21,22 @@ import com.intellij.lang.ASTNode; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; -import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiLanguageInjectionHost; import com.intellij.psi.util.PsiTreeUtil; import org.intellij.lang.regexp.*; import org.intellij.lang.regexp.psi.*; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.math.BigInteger; public final class RegExpAnnotator extends RegExpElementVisitor implements Annotator { private AnnotationHolder myHolder; + private final RegExpLanguageHosts myLanguageHosts; + + public RegExpAnnotator() { + myLanguageHosts = RegExpLanguageHosts.getInstance(); + } public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder holder) { assert myHolder == null : "unsupported concurrent annotator invocation"; @@ -95,7 +97,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot } else { final String text = ch.getUnescapedText(); - if (text.startsWith("\\") && isRedundantEscape(ch, text)) { + if (text.startsWith("\\") && myLanguageHosts.isRedundantEscape(ch, text)) { final ASTNode astNode = ch.getNode().getFirstChildNode(); if (astNode != null && astNode.getElementType() == RegExpTT.REDUNDANT_ESCAPE) { final Annotation a = myHolder.createWeakWarningAnnotation(ch, "Redundant character escape"); @@ -105,38 +107,12 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot } } - private static boolean isRedundantEscape(RegExpChar ch, String text) { - if (text.length() <= 1) return false; - RegExpLanguageHost host = findRegExpHost(ch); - if (host != null) { - final char c = text.charAt(1); - final boolean needsEscaping = host.characterNeedsEscaping(c); - return !needsEscaping; - } - else { - return !("\\]".equals(text) || "\\}".equals(text)); - } - } - - @Nullable - private static RegExpLanguageHost findRegExpHost(PsiElement element) { - PsiLanguageInjectionHost host = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element); - if (host instanceof RegExpLanguageHost) { - return (RegExpLanguageHost)host; - } - if (host != null) { - return RegExpLanguageHosts.INSTANCE.forClass(host.getClass()); - } - return null; - } - public void visitRegExpProperty(RegExpProperty property) { final ASTNode category = property.getCategoryNode(); if (category == null) { return; } - final RegExpPropertiesProvider provider = RegExpPropertiesProviders.forNode(category); - if(!provider.isValidCategory(category.getText())) { + if(!myLanguageHosts.isValidCategory(category.getPsi(), category.getText())) { final Annotation a = myHolder.createErrorAnnotation(category, "Unknown character category"); if (a != null) { // IDEA-9381 @@ -180,8 +156,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot } } if (group.isPythonNamedGroup() || group.isRubyNamedGroup()) { - RegExpLanguageHost host = findRegExpHost(group); - if (host == null || !host.supportsNamedGroupSyntax(group)) { + if (!myLanguageHosts.supportsNamedGroupSyntax(group)) { myHolder.createErrorAnnotation(group, "This named group syntax is not supported"); } } @@ -212,8 +187,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot @Override public void visitComment(PsiComment comment) { if (comment.getText().startsWith("(?#")) { - RegExpLanguageHost host = findRegExpHost(comment); - if (host == null || !host.supportsPerl5EmbeddedComments()) { + if (!myLanguageHosts.supportsPerl5EmbeddedComments(comment)) { myHolder.createErrorAnnotation(comment, "Embedded comments are not supported"); } } @@ -221,8 +195,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot @Override public void visitRegExpPyCondRef(RegExpPyCondRef condRef) { - RegExpLanguageHost host = findRegExpHost(condRef); - if (host == null || !host.supportsPythonConditionalRefs()) { + if (!myLanguageHosts.supportsPythonConditionalRefs(condRef)) { myHolder.createErrorAnnotation(condRef, "Conditional references are not supported"); } } @@ -280,8 +253,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot } } if (quantifier.getType() == RegExpQuantifier.Type.POSSESSIVE) { - RegExpLanguageHost host = findRegExpHost(quantifier); - if (host != null && !host.supportsPossessiveQuantifiers()) { + if (!myLanguageHosts.supportsPossessiveQuantifiers(quantifier)) { myHolder.createErrorAnnotation(quantifier, "Nested quantifier in regexp"); } } diff --git a/RegExpSupport/test/test/RegExpCompletionTest.java b/RegExpSupport/test/test/RegExpCompletionTest.java index 6d2fd262d7c9..a408a540a99a 100644 --- a/RegExpSupport/test/test/RegExpCompletionTest.java +++ b/RegExpSupport/test/test/RegExpCompletionTest.java @@ -19,8 +19,7 @@ import com.intellij.openapi.application.PathManager; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; import com.intellij.util.ArrayUtil; -import org.intellij.lang.regexp.RegExpLanguage; -import org.intellij.lang.regexp.RegExpPropertiesProviders; +import org.intellij.lang.regexp.DefaultRegExpPropertiesProvider; import java.io.File; import java.util.ArrayList; @@ -60,7 +59,7 @@ public class RegExpCompletionTest extends CodeInsightFixtureTestCase { private void doBackSlashVariantsTest() throws Throwable { java.util.List nameList = new ArrayList(Arrays.asList("d", "D", "s", "S", "w", "W", "b", "B", "A", "G", "Z", "z", "Q", "E", "t", "n", "r", "f", "a", "e")); - for (String[] stringArray : RegExpPropertiesProviders.getInstance().forLanguage(RegExpLanguage.INSTANCE).getAllKnownProperties()) { + for (String[] stringArray : DefaultRegExpPropertiesProvider.getInstance().getAllKnownProperties()) { nameList.add("p{" + stringArray[0] + "}"); } myFixture.testCompletionVariants(getInputDataFileName(getTestName(true)), ArrayUtil.toStringArray(nameList)); @@ -68,7 +67,7 @@ public class RegExpCompletionTest extends CodeInsightFixtureTestCase { public void testPropertyVariants() throws Throwable { java.util.List nameList = new ArrayList(); - for (String[] stringArray : RegExpPropertiesProviders.getInstance().forLanguage(RegExpLanguage.INSTANCE).getAllKnownProperties()) { + for (String[] stringArray : DefaultRegExpPropertiesProvider.getInstance().getAllKnownProperties()) { nameList.add("{" + stringArray[0] + "}"); } myFixture.testCompletionVariants(getInputDataFileName(getTestName(true)), ArrayUtil.toStringArray(nameList)); diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java index 242cac2e1489..376238573e6b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java @@ -394,6 +394,7 @@ public class GenerateEqualsHelper implements Runnable { buffer.append("return 0;\n}"); } PsiMethod hashCode = myFactory.createMethodFromText(buffer.toString(), null); + hashCode = (PsiMethod)myJavaCodeStyleManager.shortenClassReferences(hashCode); return (PsiMethod)myCodeStyleManager.reformat(hashCode); } @@ -471,7 +472,7 @@ public class GenerateEqualsHelper implements Runnable { private static void adjustHashCodeToArrays(@NonNls StringBuilder buffer, final PsiField field, final String name) { if (field.getType() instanceof PsiArrayType && hasArraysHashCode(field)) { - buffer.append("Arrays.hashCode("); + buffer.append("java.util.Arrays.hashCode("); buffer.append(name); buffer.append(")"); } diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java b/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java index 6d05e6aff9dd..21a03d7e2bc3 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java +++ b/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java @@ -16,18 +16,28 @@ package com.intellij.psi.impl; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.projectRoots.JavaSdk; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleRootManager; +import org.intellij.lang.regexp.DefaultRegExpPropertiesProvider; import org.intellij.lang.regexp.RegExpLanguageHost; import org.intellij.lang.regexp.psi.RegExpGroup; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author yole */ public class JavaRegExpHost implements RegExpLanguageHost { + + private final DefaultRegExpPropertiesProvider myPropertiesProvider; + + public JavaRegExpHost() { + myPropertiesProvider = DefaultRegExpPropertiesProvider.getInstance(); + } + @Override public boolean characterNeedsEscaping(char c) { return c == ']' || c == '}'; @@ -51,7 +61,7 @@ public class JavaRegExpHost implements RegExpLanguageHost { @Override public boolean supportsNamedGroupSyntax(RegExpGroup group) { if (group.isRubyNamedGroup()) { - final Module module = ModuleUtil.findModuleForPsiElement(group); + final Module module = ModuleUtilCore.findModuleForPsiElement(group); if (module != null) { final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); if (sdk != null && sdk.getSdkType() instanceof JavaSdk) { @@ -62,4 +72,27 @@ public class JavaRegExpHost implements RegExpLanguageHost { } return false; } + + @Override + public boolean isValidCategory(@NotNull String category) { + return myPropertiesProvider.isValidCategory(category); + } + + @NotNull + @Override + public String[][] getAllKnownProperties() { + return myPropertiesProvider.getAllKnownProperties(); + } + + @Nullable + @Override + public String getPropertyDescription(@Nullable String name) { + return myPropertiesProvider.getPropertyDescription(name); + } + + @NotNull + @Override + public String[][] getKnownCharacterClasses() { + return myPropertiesProvider.getKnownCharacterClasses(); + } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java index 04dd71c7970d..09eb7879deb9 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java @@ -583,6 +583,7 @@ public class JavaClassReference extends GenericReference implements PsiJavaRefer return myJavaClassReferenceSet; } + @NotNull @Override public String getUnresolvedMessagePattern() { return myJavaClassReferenceSet.getUnresolvedMessagePattern(myIndex); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java index 94827c3a03f5..537b3216df4d 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java @@ -60,6 +60,7 @@ public class PsiPackageReference extends PsiPolyVariantReferenceBase return subPackages.toArray(); } + @NotNull @Override public String getUnresolvedMessagePattern() { return JavaErrorMessages.message("cannot.resolve.package"); diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/daemon/JavaErrorMessages.java b/java/java-psi-impl/src/com/intellij/codeInsight/daemon/JavaErrorMessages.java index 3fc250b1c0ab..530c87cb33f4 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/daemon/JavaErrorMessages.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/daemon/JavaErrorMessages.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.daemon; import com.intellij.AbstractBundle; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.PropertyKey; /** @@ -31,6 +32,7 @@ public class JavaErrorMessages extends AbstractBundle { super(BUNDLE); } + @NotNull public static String message(@PropertyKey(resourceBundle = BUNDLE)String key, Object... params) { return INSTANCE.getMessage(key, params); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java index 63ea6bdab1cc..431665b045e2 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java @@ -1033,38 +1033,40 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } final Pair result; - if (constraint == null && methodCall instanceof PsiCallExpression) { - - final PsiExpressionList argumentList = ((PsiCallExpression)methodCall).getArgumentList(); - if (argumentList != null && preparedKey == null && PsiUtil.getLanguageLevel(argumentList).isAtLeast(LanguageLevel.JDK_1_8)) { - for (PsiExpression expression : argumentList.getExpressions()) { - if (expression instanceof PsiLambdaExpression || expression instanceof PsiMethodReferenceExpression) { - final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, false); - if (functionalInterfaceType == null || PsiUtil.resolveClassInType(functionalInterfaceType) == typeParameter){ - return getFailedInferenceConstraint(typeParameter); - } - final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType); - - final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); - if (method == null || methodParamsDependOn(typeParameter, expression, - functionalInterfaceType, method.getParameterList().getParameters(), - LambdaUtil.getSubstitutor(method, resolveResult))) { - if (expression instanceof PsiMethodReferenceExpression) { + if (constraint == null) { + if (methodCall instanceof PsiCallExpression) { + final PsiExpressionList argumentList = ((PsiCallExpression)methodCall).getArgumentList(); + if (argumentList != null && preparedKey == null && PsiUtil.getLanguageLevel(argumentList).isAtLeast(LanguageLevel.JDK_1_8)) { + for (PsiExpression expression : argumentList.getExpressions()) { + if (expression instanceof PsiLambdaExpression || expression instanceof PsiMethodReferenceExpression) { + final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, false); + if (functionalInterfaceType == null || PsiUtil.resolveClassInType(functionalInterfaceType) == typeParameter){ return getFailedInferenceConstraint(typeParameter); } - return null; + final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType); + + final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); + if (method == null || methodParamsDependOn(typeParameter, expression, + functionalInterfaceType, method.getParameterList().getParameters(), + LambdaUtil.getSubstitutor(method, resolveResult))) { + if (expression instanceof PsiMethodReferenceExpression) { + return getFailedInferenceConstraint(typeParameter); + } + return null; + } } } } - } - final PsiSubstitutor finalSubstitutor = substitutor.put(typeParameter, null); - PsiClassType[] superTypes = typeParameter.getSuperTypes(); - if (superTypes.length == 0) return null; - PsiType superType = finalSubstitutor.substitute(superTypes[0]); - if (superType == null) superType = PsiType.getJavaLangObject(manager, scope); - if (superType == null) return null; - return policy.getInferredTypeWithNoConstraint(manager, superType); + final PsiSubstitutor finalSubstitutor = substitutor.put(typeParameter, null); + PsiClassType[] superTypes = typeParameter.getSuperTypes(); + if (superTypes.length == 0) return null; + PsiType superType = finalSubstitutor.substitute(superTypes[0]); + if (superType == null) superType = PsiType.getJavaLangObject(manager, scope); + if (superType == null) return null; + return policy.getInferredTypeWithNoConstraint(manager, superType); + } + return null; } else { PsiType guess = constraint.getFirst(); diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterAbstractSuperEquals.java b/java/java-tests/testData/codeInsight/generateEquals/afterAbstractSuperEquals.java new file mode 100644 index 000000000000..61d03b795d74 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterAbstractSuperEquals.java @@ -0,0 +1,15 @@ +abstract class SuperTest { + public abstract boolean equals(Object object); +} +class Test extends SuperTest { + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + return true; + } + + public int hashCode() { + return 0; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterArrays.java b/java/java-tests/testData/codeInsight/generateEquals/afterArrays.java new file mode 100644 index 000000000000..e018a504c276 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterArrays.java @@ -0,0 +1,28 @@ +import java.util.Arrays; + +class Test { + Object[] myOs; + int[][] myIIs; + int[] myIs; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Test test = (Test) o; + + // Compare nested arrays - values of myIIs here + if (!Arrays.equals(myIs, test.myIs)) return false; + // Probably incorrect - comparing Object[] arrays with Arrays.equals + if (!Arrays.equals(myOs, test.myOs)) return false; + + return true; + } + + public int hashCode() { + int result = myOs != null ? myOs.hashCode() : 0; + result = 31 * result + (myIIs != null ? myIIs.hashCode() : 0); + result = 31 * result + (myIs != null ? myIs.hashCode() : 0); + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterArraysClass.java b/java/java-tests/testData/codeInsight/generateEquals/afterArraysClass.java new file mode 100644 index 000000000000..7a5ff00fd37f --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterArraysClass.java @@ -0,0 +1,20 @@ +class Arrays { + int[] i; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Arrays arrays = (Arrays) o; + + if (!java.util.Arrays.equals(i, arrays.i)) return false; + + return true; + } + + @Override + public int hashCode() { + return i != null ? i.hashCode() : 0; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterArraysFromJava15.java b/java/java-tests/testData/codeInsight/generateEquals/afterArraysFromJava15.java new file mode 100644 index 000000000000..cc5a036a3e24 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterArraysFromJava15.java @@ -0,0 +1,28 @@ +import java.util.Arrays; + +class Test { + Object[] myOs; + int[][] myIIs; + int[] myIs; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Test test = (Test) o; + + // Compare nested arrays - values of myIIs here + if (!Arrays.equals(myIs, test.myIs)) return false; + // Probably incorrect - comparing Object[] arrays with Arrays.equals + if (!Arrays.equals(myOs, test.myOs)) return false; + + return true; + } + + public int hashCode() { + int result = myOs != null ? Arrays.hashCode(myOs) : 0; + result = 31 * result + (myIIs != null ? Arrays.hashCode(myIIs) : 0); + result = 31 * result + (myIs != null ? Arrays.hashCode(myIs) : 0); + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterFields.java b/java/java-tests/testData/codeInsight/generateEquals/afterFields.java new file mode 100644 index 000000000000..763194e8ed96 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterFields.java @@ -0,0 +1,22 @@ +class Test { + int i; + Test a; + Test b; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Test test = (Test) o; + + if (i != test.i) return false; + if (!a.equals(test.a)) return false; + if (b != null ? !b.equals(test.b) : test.b != null) return false; + + return true; + } + + public int hashCode() { + return 0; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterHashCode.java b/java/java-tests/testData/codeInsight/generateEquals/afterHashCode.java new file mode 100644 index 000000000000..46ae180326a7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterHashCode.java @@ -0,0 +1,31 @@ +class Test { + int i; + Test a; + Test b; + double c; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Test test = (Test) o; + + if (Double.compare(test.c, c) != 0) return false; + if (i != test.i) return false; + if (!a.equals(test.a)) return false; + if (b != null ? !b.equals(test.b) : test.b != null) return false; + + return true; + } + + public int hashCode() { + int result; + long temp; + result = i; + result = 31 * result + a.hashCode(); + result = 31 * result + (b != null ? b.hashCode() : 0); + temp = c != +0.0d ? Double.doubleToLongBits(c) : 0L; + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterInsertOverride.java b/java/java-tests/testData/codeInsight/generateEquals/afterInsertOverride.java new file mode 100644 index 000000000000..142a723a06e3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterInsertOverride.java @@ -0,0 +1,20 @@ +class Test { + int i; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Test test = (Test) o; + + if (i != test.i) return false; + + return true; + } + + @Override + public int hashCode() { + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterLangClass.java b/java/java-tests/testData/codeInsight/generateEquals/afterLangClass.java new file mode 100644 index 000000000000..daf3edf8773b --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterLangClass.java @@ -0,0 +1,20 @@ +class Integer { + int i; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Integer integer = (Integer) o; + + if (i != integer.i) return false; + + return true; + } + + @Override + public int hashCode() { + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterLocalLangClass.java b/java/java-tests/testData/codeInsight/generateEquals/afterLocalLangClass.java new file mode 100644 index 000000000000..2d604e430aa1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterLocalLangClass.java @@ -0,0 +1,24 @@ +class Test { + void foo() { + class Integer { + int i; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Integer integer = (Integer) o; + + if (i != integer.i) return false; + + return true; + } + + @Override + public int hashCode() { + return i; + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterNoBaseEquals.java b/java/java-tests/testData/codeInsight/generateEquals/afterNoBaseEquals.java new file mode 100644 index 000000000000..cc6143dcf2f1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterNoBaseEquals.java @@ -0,0 +1,12 @@ +public class Test { + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + return true; + } + + public int hashCode() { + return 0; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterNotNull.java b/java/java-tests/testData/codeInsight/generateEquals/afterNotNull.java new file mode 100644 index 000000000000..0ca118388bdb --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterNotNull.java @@ -0,0 +1,18 @@ +class Test { + @org.jetbrains.annotations.NotNull Object d; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Test test = (Test) o; + + if (d != null ? !d.equals(test.d) : test.d != null) return false; + + return true; + } + + public int hashCode() { + return d != null ? d.hashCode() : 0; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterOneDoubleField.java b/java/java-tests/testData/codeInsight/generateEquals/afterOneDoubleField.java new file mode 100644 index 000000000000..1c47228b9e66 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterOneDoubleField.java @@ -0,0 +1,19 @@ +class Test { + double d; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Test test = (Test) o; + + if (Double.compare(test.d, d) != 0) return false; + + return true; + } + + public int hashCode() { + final long temp = d != +0.0d ? Double.doubleToLongBits(d) : 0L; + return (int) (temp ^ (temp >>> 32)); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterOneField.java b/java/java-tests/testData/codeInsight/generateEquals/afterOneField.java new file mode 100644 index 000000000000..d8a067833c50 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterOneField.java @@ -0,0 +1,18 @@ +class Test { + Object d; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Test test = (Test) o; + + if (d != null ? !d.equals(test.d) : test.d != null) return false; + + return true; + } + + public int hashCode() { + return d != null ? d.hashCode() : 0; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterOneFloatField.java b/java/java-tests/testData/codeInsight/generateEquals/afterOneFloatField.java new file mode 100644 index 000000000000..f449b757c688 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterOneFloatField.java @@ -0,0 +1,18 @@ +class Test { + float d; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Test test = (Test) o; + + if (Float.compare(test.d, d) != 0) return false; + + return true; + } + + public int hashCode() { + return (d != +0.0f ? Float.floatToIntBits(d) : 0); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterPrimitiveFields.java b/java/java-tests/testData/codeInsight/generateEquals/afterPrimitiveFields.java new file mode 100644 index 000000000000..3ccd0e0e9937 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterPrimitiveFields.java @@ -0,0 +1,22 @@ +public class Test { + int f; + public int j; + int h; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Test test = (Test) o; + + if (f != test.f) return false; + if (h != test.h) return false; + if (j != test.j) return false; + + return true; + } + + public int hashCode() { + return 0; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterSuperEquals.java b/java/java-tests/testData/codeInsight/generateEquals/afterSuperEquals.java new file mode 100644 index 000000000000..0cf488afa972 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterSuperEquals.java @@ -0,0 +1,17 @@ +abstract class SuperTest { + public boolean equals(Object object) { + return true; + } + public int hashCode() { + return 0; + } +} +class Test extends SuperTest { + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + return true; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeAbstractSuperEquals.java b/java/java-tests/testData/codeInsight/generateEquals/beforeAbstractSuperEquals.java new file mode 100644 index 000000000000..37b74df4587d --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeAbstractSuperEquals.java @@ -0,0 +1,5 @@ +abstract class SuperTest { + public abstract boolean equals(Object object); +} +class Test extends SuperTest { +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeArrays.java b/java/java-tests/testData/codeInsight/generateEquals/beforeArrays.java new file mode 100644 index 000000000000..1d99c4fa4160 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeArrays.java @@ -0,0 +1,5 @@ +class Test { + Object[] myOs; + int[][] myIIs; + int[] myIs; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeArraysClass.java b/java/java-tests/testData/codeInsight/generateEquals/beforeArraysClass.java new file mode 100644 index 000000000000..6e8a0cc18683 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeArraysClass.java @@ -0,0 +1,3 @@ +class Arrays { + int[] i; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeArraysFromJava15.java b/java/java-tests/testData/codeInsight/generateEquals/beforeArraysFromJava15.java new file mode 100644 index 000000000000..1d99c4fa4160 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeArraysFromJava15.java @@ -0,0 +1,5 @@ +class Test { + Object[] myOs; + int[][] myIIs; + int[] myIs; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeFields.java b/java/java-tests/testData/codeInsight/generateEquals/beforeFields.java new file mode 100644 index 000000000000..014c0cd40946 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeFields.java @@ -0,0 +1,5 @@ +class Test { + int i; + Test a; + Test b; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeHashCode.java b/java/java-tests/testData/codeInsight/generateEquals/beforeHashCode.java new file mode 100644 index 000000000000..fbea244fe5b5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeHashCode.java @@ -0,0 +1,6 @@ +class Test { + int i; + Test a; + Test b; + double c; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeInsertOverride.java b/java/java-tests/testData/codeInsight/generateEquals/beforeInsertOverride.java new file mode 100644 index 000000000000..0694e03bdeeb --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeInsertOverride.java @@ -0,0 +1,3 @@ +class Test { + int i; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeLangClass.java b/java/java-tests/testData/codeInsight/generateEquals/beforeLangClass.java new file mode 100644 index 000000000000..7efa66787d6d --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeLangClass.java @@ -0,0 +1,3 @@ +class Integer { + int i; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeLocalLangClass.java b/java/java-tests/testData/codeInsight/generateEquals/beforeLocalLangClass.java new file mode 100644 index 000000000000..950e3d6120d1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeLocalLangClass.java @@ -0,0 +1,7 @@ +class Test { + void foo() { + class Integer { + int i; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeNoBaseEquals.java b/java/java-tests/testData/codeInsight/generateEquals/beforeNoBaseEquals.java new file mode 100644 index 000000000000..518efb8d3010 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeNoBaseEquals.java @@ -0,0 +1,2 @@ +public class Test { +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeNotNull.java b/java/java-tests/testData/codeInsight/generateEquals/beforeNotNull.java new file mode 100644 index 000000000000..19b04f5d38a5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeNotNull.java @@ -0,0 +1,3 @@ +class Test { + @org.jetbrains.annotations.NotNull Object d; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeOneDoubleField.java b/java/java-tests/testData/codeInsight/generateEquals/beforeOneDoubleField.java new file mode 100644 index 000000000000..13973f7e09f8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeOneDoubleField.java @@ -0,0 +1,3 @@ +class Test { + double d; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeOneField.java b/java/java-tests/testData/codeInsight/generateEquals/beforeOneField.java new file mode 100644 index 000000000000..66266e6522ca --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeOneField.java @@ -0,0 +1,3 @@ +class Test { + Object d; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeOneFloatField.java b/java/java-tests/testData/codeInsight/generateEquals/beforeOneFloatField.java new file mode 100644 index 000000000000..36d4f187fafc --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeOneFloatField.java @@ -0,0 +1,3 @@ +class Test { + float d; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforePrimitiveFields.java b/java/java-tests/testData/codeInsight/generateEquals/beforePrimitiveFields.java new file mode 100644 index 000000000000..154fdf0005d1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforePrimitiveFields.java @@ -0,0 +1,5 @@ +public class Test { + int f; + public int j; + int h; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeSuperEquals.java b/java/java-tests/testData/codeInsight/generateEquals/beforeSuperEquals.java new file mode 100644 index 000000000000..ad4972c3b72e --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeSuperEquals.java @@ -0,0 +1,10 @@ +abstract class SuperTest { + public boolean equals(Object object) { + return true; + } + public int hashCode() { + return 0; + } +} +class Test extends SuperTest { +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java new file mode 100644 index 000000000000..9026d776f077 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java @@ -0,0 +1,10 @@ +package com.intellij.codeInsight; + +/** + * @author dsl + */ +public class GenerateEquals15Test extends GenerateEqualsTestCase { + public void testArraysFromJava15() throws Exception { + doTest(new int[]{0, 1, 2}, new int[]{0, 1, 2}, new int[0], false); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEqualsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEqualsTest.java new file mode 100644 index 000000000000..60fbd7428679 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEqualsTest.java @@ -0,0 +1,74 @@ +package com.intellij.codeInsight; + +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; + +/** + * @author dsl + */ +public class GenerateEqualsTest extends GenerateEqualsTestCase { + public void testNoBaseEquals() throws Exception { + doTest(new int[0], new int[0], new int[0], false); + } + + public void testPrimitiveFields() throws Exception { + doTest(new int[]{0, 1, 2}, new int[0], new int[0], false); + } + + public void testFields() throws Exception { + doTest(new int[]{0, 1, 2}, new int[0], new int[]{1}, false); + } + + public void testAbstractSuperEquals() throws Exception { + doTest(new int[0], new int[0], new int[0], false); + } + + public void testSuperEquals() throws Exception { + doTest(new int[0], new int[0], new int[0], false); + } + + public void testHashCode() throws Exception { + doTest(new int[]{0, 1, 2, 3}, new int[]{0, 1, 2, 3}, new int[]{1}, false); + } + + public void testArrays() throws Exception { + doTest(new int[]{0, 1, 2}, new int[]{0, 1, 2}, new int[0], false); + } + + public void testOneDoubleField() throws Exception { + doTest(new int[]{0}, new int[]{0}, new int[0], false); + } + + public void testOneFloatField() throws Exception { + doTest(new int[]{0}, new int[]{0}, new int[0], false); + } + + public void testOneField() throws Exception { + doTest(new int[]{0}, new int[]{0}, new int[0], false); + } + + public void testNotNull() throws Exception { + doTest(new int[]{0}, new int[]{0}, new int[0], false); + } + + public void testInsertOverride() throws Exception { + doTest(new int[]{0}, new int[]{0}, new int[0], true); + } + + public void testLangClass() throws Exception { + doTest(new int[]{0}, new int[]{0}, new int[0], true); + } + + public void testLocalLangClass() throws Exception { + doTest(new int[]{0}, new int[]{0}, new int[0], true); + } + + public void testArraysClass() throws Exception { + doTest(new int[]{0}, new int[]{0}, new int[0], true); + } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk14(); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEqualsTestCase.java b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEqualsTestCase.java new file mode 100644 index 000000000000..6a0ce2077051 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEqualsTestCase.java @@ -0,0 +1,53 @@ +package com.intellij.codeInsight; + +import com.intellij.codeInsight.generation.GenerateEqualsHelper; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.testFramework.LightCodeInsightTestCase; + +import java.util.ArrayList; + +/** + * @author yole + */ +public abstract class GenerateEqualsTestCase extends LightCodeInsightTestCase { + protected void doTest(int[] equals, int[] hashCode, int[] nonNull, boolean insertOverride) throws Exception { + configureByFile("/codeInsight/generateEquals/before" + getTestName(false) + ".java"); + performTest(equals, hashCode, nonNull, insertOverride); + checkResultByFile("/codeInsight/generateEquals/after" + getTestName(false) + ".java"); + } + + private static void performTest(int[] equals, int[] hashCode, int[] nonNull, boolean insertOverride) { + CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()).clone(); + settings.GENERATE_FINAL_LOCALS = true; + settings.INSERT_OVERRIDE_ANNOTATION = insertOverride; + CodeStyleSettingsManager.getInstance(getProject()).setTemporarySettings(settings); + try { + PsiElement element = getFile().findElementAt(getEditor().getCaretModel().getOffset()); + if (element == null) return; + PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); + if (aClass == null) return; + PsiField[] fields = aClass.getFields(); + new GenerateEqualsHelper(getProject(), aClass, getIndexed(fields, equals), getIndexed(fields, hashCode), getIndexed(fields, nonNull), + false) + .invoke(); + FileDocumentManager.getInstance().saveAllDocuments(); + } + finally { + CodeStyleSettingsManager.getInstance(getProject()).dropTemporarySettings(); + } + } + + private static PsiField[] getIndexed(PsiField[] fields, int[] indices) { + ArrayList result = new ArrayList(); + for (int indice : indices) { + result.add(fields[indice]); + } + return result.toArray(new PsiField[result.size()]); + } +} diff --git a/java/jdkAnnotations/java/text/annotations.xml b/java/jdkAnnotations/java/text/annotations.xml index 3a1d14aa4e0a..44cf7daebd28 100644 --- a/java/jdkAnnotations/java/text/annotations.xml +++ b/java/jdkAnnotations/java/text/annotations.xml @@ -1,5 +1,37 @@ + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/jsp-base-openapi/src/com/intellij/lang/jsp/JspVersion.java b/java/jsp-base-openapi/src/com/intellij/lang/jsp/JspVersion.java index 207b7c56ca8a..7e5416d69b93 100644 --- a/java/jsp-base-openapi/src/com/intellij/lang/jsp/JspVersion.java +++ b/java/jsp-base-openapi/src/com/intellij/lang/jsp/JspVersion.java @@ -54,6 +54,17 @@ public interface JspVersion { } }; + JspVersion JSP_2_3 = new JspVersion() { + + public String getNumber() { + return "2.3"; + } + + public boolean betterThan(JspVersion other) { + return getNumber().compareTo(other.getNumber()) > 0; + } + }; + String getNumber(); boolean betterThan(JspVersion other); diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java index 58b6a4ca4aba..db367a6d56d5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/JavaBuilderUtil.java @@ -67,9 +67,6 @@ public class JavaBuilderUtil { ModuleChunk chunk, Collection filesToCompile, Collection successfullyCompiled) throws IOException { - if (Utils.errorsDetected(context)) { - return false; - } try { boolean additionalPassRequired = false; @@ -161,6 +158,14 @@ public class JavaBuilderUtil { globalMappings.differentiateOnRebuild(delta); } + if (Utils.errorsDetected(context)) { + // important: perform dependency analysis and mark found dependencies even if there were errors during the first phase of make. + // Integration of changes should happen only if the corresponding phase of make succeeds + // In case of errors this wil ensure that all dependencies marked after the first phase + // will be compiled during the first phase of the next make + return false; + } + context.processMessage(new ProgressMessage("Updating dependency information... [" + chunk.getName() + "]")); globalMappings.integrate(delta); diff --git a/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java b/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java index a64fe860486d..35026e9d64eb 100644 --- a/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java +++ b/platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java @@ -596,7 +596,7 @@ public abstract class GlobalSearchScope extends SearchScope implements ProjectAw } } - private static class FilesScope extends GlobalSearchScope { + public static class FilesScope extends GlobalSearchScope { private final Collection myFiles; public FilesScope(final Project project, final Collection files) { diff --git a/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderAdapter.java b/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderAdapter.java index 49ff31dd0b26..6d32701a79fd 100644 --- a/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderAdapter.java +++ b/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderAdapter.java @@ -32,6 +32,10 @@ public class PsiBuilderAdapter implements PsiBuilder { myDelegate = delegate; } + public PsiBuilder getDelegate() { + return myDelegate; + } + @Override public Project getProject() { return myDelegate.getProject(); diff --git a/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java b/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java index c69755ba7002..e0d559f1cbbc 100644 --- a/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java +++ b/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java @@ -22,7 +22,10 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.psi.PsiErrorElement; import com.intellij.psi.PsiFile; import com.intellij.psi.TokenType; @@ -31,14 +34,16 @@ import com.intellij.psi.impl.source.resolve.FileContextUtil; import com.intellij.psi.impl.source.text.BlockSupportImpl; import com.intellij.psi.impl.source.text.DiffLog; import com.intellij.psi.impl.source.tree.*; -import com.intellij.psi.impl.source.tree.Factory; import com.intellij.psi.text.BlockSupport; import com.intellij.psi.tree.*; import com.intellij.util.CharTable; import com.intellij.util.ExceptionUtil; import com.intellij.util.ThreeState; import com.intellij.util.TripleFunction; -import com.intellij.util.containers.*; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Convertor; +import com.intellij.util.containers.LimitedPool; +import com.intellij.util.containers.Stack; import com.intellij.util.diff.DiffTreeChangeBuilder; import com.intellij.util.diff.FlyweightCapableTreeStructure; import com.intellij.util.diff.ShallowNodeComparator; @@ -798,7 +803,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder, AS clearCachedTokenType(); } - private boolean whitespaceOrComment(IElementType token) { + public boolean whitespaceOrComment(IElementType token) { return myWhitespaces.contains(token) || myComments.contains(token); } diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerContainerImpl.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerContainerImpl.java index 6173a7403c1e..107f3f581267 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerContainerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerContainerImpl.java @@ -49,7 +49,7 @@ public class VirtualFilePointerContainerImpl extends TraceableDisposable impleme private final VirtualFilePointerListener myListener; private volatile Trinity myCachedThings; private volatile long myTimeStampOfCachedThings = -1; - @NonNls private static final String URL_ATTR = "url"; + @NonNls public static final String URL_ATTR = "url"; private boolean myDisposed; private static final boolean TRACE_CREATION = LOG.isDebugEnabled() || ApplicationManager.getApplication().isUnitTestMode(); diff --git a/platform/lang-api/src/com/intellij/codeInsight/daemon/EmptyResolveMessageProvider.java b/platform/lang-api/src/com/intellij/codeInsight/daemon/EmptyResolveMessageProvider.java index 2fb1dea8aea8..0cba5404e11b 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/daemon/EmptyResolveMessageProvider.java +++ b/platform/lang-api/src/com/intellij/codeInsight/daemon/EmptyResolveMessageProvider.java @@ -16,6 +16,8 @@ package com.intellij.codeInsight.daemon; +import org.jetbrains.annotations.NotNull; + /** * Implement this in your {@link com.intellij.psi.PsiReference} to provide custom error message. */ @@ -27,5 +29,6 @@ public interface EmptyResolveMessageProvider { * @return pattern or message * @see XmlHighlightVisitor#getErrorDescription() */ + @NotNull String getUnresolvedMessagePattern(); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightingSettingsPerFile.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightingSettingsPerFile.java index 5fda4d7037e5..a7c6c4556020 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightingSettingsPerFile.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightingSettingsPerFile.java @@ -59,13 +59,15 @@ public class HighlightingSettingsPerFile implements PersistentStateComponent filtered = - DumbService.getInstance(project).filterByDumbAwareness(Arrays.asList(providers)); - for (DefaultHighlightingSettingProvider p : filtered) { - FileHighlighingSetting setting = p.getDefaultSetting(project, virtualFile); - if (setting != null) { - return setting; + if (virtualFile != null) { + DefaultHighlightingSettingProvider[] providers = DefaultHighlightingSettingProvider.EP_NAME.getExtensions(); + List filtered = + DumbService.getInstance(project).filterByDumbAwareness(Arrays.asList(providers)); + for (DefaultHighlightingSettingProvider p : filtered) { + FileHighlighingSetting setting = p.getDefaultSetting(project, virtualFile); + if (setting != null) { + return setting; + } } } return FileHighlighingSetting.FORCE_HIGHLIGHTING; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java index fe1b4496139f..3880ca5872e1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java @@ -21,6 +21,7 @@ import com.intellij.lang.parameterInfo.ParameterInfoUIContextEx; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import com.intellij.ui.Gray; +import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.SideBorder; import com.intellij.ui.StrikeoutLabel; import com.intellij.util.ui.UIUtil; @@ -55,7 +56,7 @@ class ParameterInfoComponent extends JPanel{ protected int myWidthLimit; public ParameterInfoComponent(Object[] objects, Editor editor,@NotNull ParameterInfoHandler handler) { - super(new GridBagLayout()); + super(new BorderLayout()); JComponent editorComponent = editor.getComponent(); JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane(); @@ -66,19 +67,36 @@ class ParameterInfoComponent extends JPanel{ myObjects = objects; - setLayout(new GridBagLayout()); setBackground(BACKGROUND_COLOR); myHandler = handler; myPanels = new OneElementComponent[myObjects.length]; + final JPanel panel = new JPanel(new GridBagLayout()); for(int i = 0; i < myObjects.length; i++) { myPanels[i] = new OneElementComponent(); - add(myPanels[i], new GridBagConstraints(0,i,1,1,1,0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0)); + panel.add(myPanels[i], new GridBagConstraints(0,i,1,1,1,0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0)); } + final JScrollPane pane = ScrollPaneFactory.createScrollPane(panel); + pane.setBorder(null); + pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + add(pane, BorderLayout.CENTER); + myCurrentParameterIndex = -1; } + @Override + public Dimension getPreferredSize() { + int size = myPanels.length; + final Dimension preferredSize = super.getPreferredSize(); + if (size >= 0 && size <= 20) { + return preferredSize; + } + else { + return new Dimension(preferredSize.width + 20, 200); + } + } + public Object getHighlighted() { return myHighlighted; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/FileLevelIntentionComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/FileLevelIntentionComponent.java index 65adeb9dfa31..009ca7f10a0e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/FileLevelIntentionComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/FileLevelIntentionComponent.java @@ -49,6 +49,7 @@ public class FileLevelIntentionComponent extends EditorNotificationPanel { final List> intentions, final Project project, final PsiFile psiFile, final Editor editor) { myProject = project; + myBackground = getColor(severity); final ShowIntentionsPass.IntentionsInfo info = new ShowIntentionsPass.IntentionsInfo(); @@ -72,7 +73,6 @@ public class FileLevelIntentionComponent extends EditorNotificationPanel { myLabel.setText(description); myLabel.setIcon(SeverityRegistrar.getInstance(project).compare(severity, HighlightSeverity.ERROR) >= 0 ? AllIcons.Actions.QuickfixBulb : AllIcons.Actions.IntentionBulb); - myBackground = getColor(severity); new ClickListener() { @Override diff --git a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java new file mode 100644 index 000000000000..fd0860fbe45d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java @@ -0,0 +1,795 @@ +// This class is a runtime engine for parsers generated by Grammar-Kit. +// Do not modify or refactor without complete investigation and/or review. +package com.intellij.lang.parser; + +import com.intellij.lang.*; +import com.intellij.lang.impl.PsiBuilderAdapter; +import com.intellij.lang.impl.PsiBuilderImpl; +import com.intellij.lexer.Lexer; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringHash; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiReference; +import com.intellij.psi.TokenType; +import com.intellij.psi.impl.source.resolve.FileContextUtil; +import com.intellij.psi.impl.source.tree.CompositePsiElement; +import com.intellij.psi.tree.ICompositeElementType; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.Function; +import com.intellij.util.containers.LimitedPool; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; + +/** + * @author gregsh + */ +@SuppressWarnings("StringEquality") +public class GeneratedParserUtilBase { + + private static final Logger LOG = Logger.getInstance("com.intellij.lang.parser.GeneratedParserUtilBase"); + + public static final IElementType DUMMY_BLOCK = new DummyBlockElementType(); + + public interface Parser { + boolean parse(PsiBuilder builder, int level); + } + + public static final Parser TOKEN_ADVANCER = new Parser() { + @Override + public boolean parse(PsiBuilder builder, int level) { + if (builder.eof()) return false; + builder.advanceLexer(); + return true; + } + }; + + public static final Parser TRUE_CONDITION = new Parser() { + @Override + public boolean parse(PsiBuilder builder, int level) { + return true; + } + }; + + public static boolean eof(PsiBuilder builder_, int level_) { + return builder_.eof(); + } + + public static boolean recursion_guard_(PsiBuilder builder_, int level_, String funcName_) { + if (level_ > 1000) { + builder_.error("Maximum recursion level (" + 1000 + ") reached in " + funcName_); + return false; + } + return true; + } + + public static void empty_element_parsed_guard_(PsiBuilder builder_, int offset_, String funcName_) { + builder_.error("Empty element parsed in " + funcName_ +" at offset " + offset_); + } + + public static boolean invalid_left_marker_guard_(PsiBuilder builder_, PsiBuilder.Marker marker_, String funcName_) { + //builder_.error("Invalid left marker encountered in " + funcName_ +" at offset " + builder_.getCurrentOffset()); + boolean goodMarker = marker_ != null && ((LighterASTNode)marker_).getTokenType() != TokenType.ERROR_ELEMENT; + if (!goodMarker) return false; + ErrorState state = ErrorState.get(builder_); + + Frame frame = state.frameStack.isEmpty() ? null : state.frameStack.getLast(); + return frame == null || frame.errorReportedAt <= builder_.getCurrentOffset(); + } + + public static boolean consumeTokens(PsiBuilder builder_, int pin_, IElementType... tokens_) { + ErrorState state = ErrorState.get(builder_); + if (state.completionState != null && state.predicateSign) { + addCompletionVariant(builder_, state, state.completionState, tokens_, builder_.getCurrentOffset()); + } + // suppress single token completion + CompletionState completionState = state.completionState; + state.completionState = null; + boolean result_ = true; + boolean pinned_ = false; + for (int i = 0, tokensLength = tokens_.length; i < tokensLength; i++) { + if (pin_ > 0 && i == pin_) pinned_ = result_; + if ((result_ || pinned_) && !consumeToken(builder_, tokens_[i])) { + result_ = false; + if (pin_ < 0 || pinned_) report_error_(builder_, state, false); + } + } + state.completionState = completionState; + return pinned_ || result_; + } + + public static boolean consumeToken(PsiBuilder builder_, IElementType token) { + if (nextTokenIsInner(builder_, token, true)) { + builder_.advanceLexer(); + return true; + } + return false; + } + + public static boolean consumeTokenFast(PsiBuilder builder_, IElementType token) { + if (builder_.getTokenType() == token) { + builder_.advanceLexer(); + return true; + } + return false; + } + + public static boolean consumeTokenFast(PsiBuilder builder_, String text) { + if (Comparing.strEqual(builder_.getTokenText(), text, ErrorState.get(builder_).caseSensitive)) { + builder_.advanceLexer(); + return true; + } + return false; + } + + public static boolean nextTokenIsFast(PsiBuilder builder_, IElementType token) { + return builder_.getTokenType() == token; + } + + public static boolean nextTokenIs(PsiBuilder builder_, IElementType token) { + return nextTokenIsInner(builder_, token, false); + } + + public static boolean nextTokenIsInner(PsiBuilder builder_, IElementType token, boolean force) { + ErrorState state = ErrorState.get(builder_); + if (state.completionState != null && !force) return true; + IElementType tokenType = builder_.getTokenType(); + if (!state.suppressErrors && state.predicateCount < 2) { + addVariant(builder_, state, token); + } + return token == tokenType; + } + + public static boolean replaceVariants(PsiBuilder builder_, int variantCount, String frameName) { + ErrorState state = ErrorState.get(builder_); + if (!state.suppressErrors && state.predicateCount < 2 && state.predicateSign) { + state.clearVariants(true, state.variants.size() - variantCount); + addVariantInner(state, builder_.getCurrentOffset(), frameName); + } + return true; + } + + public static void addVariant(PsiBuilder builder_, String text) { + addVariant(builder_, ErrorState.get(builder_), text); + } + + private static void addVariant(PsiBuilder builder_, ErrorState state, Object o) { + int offset = builder_.getCurrentOffset(); + addVariantInner(state, offset, o); + + CompletionState completionState = state.completionState; + if (completionState != null && state.predicateSign) { + addCompletionVariant(builder_, state, completionState, o, offset); + } + } + + private static void addVariantInner(ErrorState state, int offset, Object o) { + Variant variant = state.VARIANTS.alloc().init(offset, o); + if (state.predicateSign) { + state.variants.add(variant); + if (state.lastExpectedVariantOffset < variant.offset) { + state.lastExpectedVariantOffset = variant.offset; + } + } + else { + state.unexpected.add(variant); + } + } + + public static boolean consumeToken(PsiBuilder builder_, String text) { + ErrorState state = ErrorState.get(builder_); + if (!state.suppressErrors && state.predicateCount < 2) { + addVariant(builder_, state, text); + } + return consumeTokenInner(builder_, text, state.caseSensitive); + } + + public static boolean consumeTokenInner(PsiBuilder builder_, String text, boolean caseSensitive) { + final CharSequence sequence = builder_.getOriginalText(); + final int offset = builder_.getCurrentOffset(); + final int endOffset = offset + text.length(); + CharSequence tokenText = sequence.subSequence(offset, Math.min(endOffset, sequence.length())); + + if (Comparing.equal(text, tokenText, caseSensitive)) { + int count = 0; + while (true) { + final int nextOffset = builder_.rawTokenTypeStart(++ count); + if (nextOffset > endOffset) { + return false; + } + else if (nextOffset == endOffset) { + break; + } + } + while (count-- > 0) builder_.advanceLexer(); + return true; + } + return false; + } + + private static void addCompletionVariant(PsiBuilder builder_, + ErrorState state, + CompletionState completionState, + Object o, + int offset) { + boolean add = false; + int diff = completionState.offset - offset; + String text = completionState.convertItem(o); + int length = text == null? 0 : text.length(); + if (length == 0) return; + if (diff == 0) { + add = true; + } + else if (diff > 0 && diff <= length) { + CharSequence fragment = builder_.getOriginalText().subSequence(offset, completionState.offset); + add = StringUtil.startsWithIgnoreCase(text, fragment.toString()); + } + else if (diff < 0) { + for (int i=-1; ; i--) { + IElementType type = builder_.rawLookup(i); + int tokenStart = builder_.rawTokenTypeStart(i); + if (((PsiBuilderImpl)((Builder)builder_).getDelegate()).whitespaceOrComment(type)) { + diff = completionState.offset - tokenStart; + } + else if (type != null && tokenStart < completionState.offset) { + CharSequence fragment = builder_.getOriginalText().subSequence(tokenStart, completionState.offset); + if (StringUtil.startsWithIgnoreCase(text, fragment.toString())) { + diff = completionState.offset - tokenStart; + } + break; + } + else break; + } + add = diff >= 0 && diff < length; + } + add = add && length > 1 && !(text.charAt(0) == '<' && text.charAt(length - 1) == '>') && + !(text.charAt(0) == '\'' && text.charAt(length - 1) == '\'' && length < 5); + if (add) { + completionState.items.add(text); + } + } + + + public static final String _SECTION_NOT_ = "_SECTION_NOT_"; + public static final String _SECTION_AND_ = "_SECTION_AND_"; + public static final String _SECTION_RECOVER_ = "_SECTION_RECOVER_"; + public static final String _SECTION_GENERAL_ = "_SECTION_GENERAL_"; + + public static void enterErrorRecordingSection(PsiBuilder builder_, int level, @NotNull String sectionType, @Nullable String frameName) { + ErrorState state = ErrorState.get(builder_); + Frame frame = state.FRAMES.alloc().init(builder_.getCurrentOffset(), level, sectionType, frameName, state.variants.size()); + state.frameStack.add(frame); + if (sectionType == _SECTION_AND_) { + if (state.predicateCount == 0 && !state.predicateSign) { + throw new AssertionError("Incorrect false predicate sign"); + } + state.predicateCount++; + } + else if (sectionType == _SECTION_NOT_) { + if (state.predicateCount == 0) { + state.predicateSign = false; + } + else { + state.predicateSign = !state.predicateSign; + } + state.predicateCount++; + } + } + + public static boolean exitErrorRecordingSection(PsiBuilder builder_, + int level, + boolean result, + boolean pinned, + @NotNull String sectionType, + @Nullable Parser eatMore) { + ErrorState state = ErrorState.get(builder_); + + Frame frame = state.frameStack.pollLast(); + int initialOffset = builder_.getCurrentOffset(); + if (frame == null || level != frame.level || !sectionType.equals(frame.section)) { + LOG.error("Unbalanced error section: got " + new Frame().init(initialOffset, level, sectionType, "", 0) + ", expected " + frame); + if (frame != null) state.FRAMES.recycle(frame); + return result; + } + if (sectionType == _SECTION_AND_ || sectionType == _SECTION_NOT_) { + state.predicateCount--; + if (sectionType == _SECTION_NOT_) state.predicateSign = !state.predicateSign; + state.FRAMES.recycle(frame); + return result; + } + if (!result && !pinned && initialOffset == frame.offset && state.lastExpectedVariantOffset == frame.offset && + frame.name != null && state.variants.size() - frame.variantCount > 1) { + state.clearVariants(true, frame.variantCount); + addVariantInner(state, initialOffset, frame.name); + } + if (sectionType == _SECTION_RECOVER_ && !state.suppressErrors && eatMore != null) { + state.suppressErrors = true; + final boolean eatMoreFlagOnce = !builder_.eof() && eatMore.parse(builder_, frame.level + 1); + final int lastErrorPos = getLastVariantOffset(state, initialOffset); + boolean eatMoreFlag = eatMoreFlagOnce || !result && frame.offset == initialOffset && lastErrorPos > frame.offset; + + final LighterASTNode latestDoneMarker = + (pinned || result) && (state.altMode || lastErrorPos > initialOffset) && + eatMoreFlagOnce ? builder_.getLatestDoneMarker() : null; + PsiBuilder.Marker extensionMarker = null; + IElementType extensionTokenType = null; + if (latestDoneMarker instanceof PsiBuilder.Marker && frame.offset == latestDoneMarker.getStartOffset()) { + extensionMarker = ((PsiBuilder.Marker)latestDoneMarker).precede(); + extensionTokenType = latestDoneMarker.getTokenType(); + ((PsiBuilder.Marker)latestDoneMarker).drop(); + } + // advance to the last error pos + // skip tokens until lastErrorPos. parseAsTree might look better here... + int parenCount = 0; + while ((eatMoreFlag || parenCount > 0) && builder_.getCurrentOffset() < lastErrorPos) { + if (state.braces != null) { + if (builder_.getTokenType() == state.braces[0].getLeftBraceType()) parenCount ++; + else if (builder_.getTokenType() == state.braces[0].getRightBraceType()) parenCount --; + } + builder_.advanceLexer(); + eatMoreFlag = eatMore.parse(builder_, frame.level + 1); + } + boolean errorReported = frame.errorReportedAt == initialOffset; + if (errorReported) { + if (eatMoreFlag) { + builder_.advanceLexer(); + parseAsTree(state, builder_, frame.level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER, eatMore); + } + } + else if (eatMoreFlag) { + errorReported = reportError(builder_, state, true, true); + parseAsTree(state, builder_, frame.level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER, eatMore); + } + else if (eatMoreFlagOnce || (!result && frame.offset != builder_.getCurrentOffset())) { + errorReported = reportError(builder_, state, true, false); + } + if (extensionMarker != null) { + extensionMarker.done(extensionTokenType); + } + state.suppressErrors = false; + if (errorReported || result) { + state.clearVariants(true, 0); + state.clearVariants(false, 0); + state.lastExpectedVariantOffset = -1; + } + if (!result && eatMoreFlagOnce && frame.offset != builder_.getCurrentOffset()) result = true; + } + else if (!result && pinned && frame.errorReportedAt < 0) { + // do not report if there're errors after current offset + if (getLastVariantOffset(state, initialOffset) == initialOffset) { + // do not force, inner recoverRoot might have skipped some tokens + if (reportError(builder_, state, false, false)) { + frame.errorReportedAt = initialOffset; + } + } + } + // propagate errorReportedAt up the stack to avoid duplicate reporting + Frame prevFrame = state.frameStack.isEmpty() ? null : state.frameStack.getLast(); + if (prevFrame != null && prevFrame.errorReportedAt < frame.errorReportedAt) prevFrame.errorReportedAt = frame.errorReportedAt; + state.FRAMES.recycle(frame); + return result; + } + + public static boolean report_error_(PsiBuilder builder_, boolean result_) { + if (!result_) report_error_(builder_, ErrorState.get(builder_), false); + return result_; + } + + public static void report_error_(PsiBuilder builder_, ErrorState state, boolean advance) { + Frame frame = state.frameStack.isEmpty()? null : state.frameStack.getLast(); + if (frame == null) { + LOG.error("Unbalanced error section: got null , expected " + frame); + return; + } + int offset = builder_.getCurrentOffset(); + if (frame.errorReportedAt < offset && getLastVariantOffset(state, builder_.getCurrentOffset()) <= offset) { + if (reportError(builder_, state, true, advance)) { + frame.errorReportedAt = offset; + } + } + } + + private static int getLastVariantOffset(ErrorState state, int defValue) { + return state.lastExpectedVariantOffset < 0? defValue : state.lastExpectedVariantOffset; + } + + private static boolean reportError(PsiBuilder builder_, ErrorState state, boolean force, boolean advance) { + String expectedText = state.getExpectedText(builder_); + boolean notEmpty = StringUtil.isNotEmpty(expectedText); + if (force || notEmpty || advance) { + String gotText = builder_.eof()? "unexpected end of file" : + notEmpty? "got '" + builder_.getTokenText() +"'" : + "'" + builder_.getTokenText() +"' unexpected"; + String message = expectedText + gotText; + if (advance) { + PsiBuilder.Marker mark = builder_.mark(); + builder_.advanceLexer(); + mark.error(message); + } + else { + builder_.error(message); + } + return true; + } + return false; + } + + + public static final Key COMPLETION_STATE_KEY = Key.create("COMPLETION_STATE_KEY"); + + public static class CompletionState implements Function { + public final int offset; + public final Collection items = new THashSet(); + + public CompletionState(int offset) { + this.offset = offset; + } + + @Nullable + public String convertItem(Object o) { + return o instanceof Object[] ? StringUtil.join((Object[]) o, this, " ") : o.toString(); + } + + @Override + public String fun(Object o) { + return o.toString(); + } + } + + public static class Builder extends PsiBuilderAdapter { + public final ErrorState state; + public final PsiParser parser; + + public Builder(PsiBuilder builder, ErrorState state, PsiParser parser) { + super(builder); + this.state = state; + this.parser = parser; + } + + public Lexer getLexer() { + return ((PsiBuilderImpl)myDelegate).getLexer(); + } + } + + public static PsiBuilder adapt_builder_(IElementType root, PsiBuilder builder, PsiParser parser) { + ErrorState state = new ErrorState(); + ErrorState.initState(root, builder, state); + return new Builder(builder, state, parser); + } + + public static class ErrorState { + int predicateCount; + boolean predicateSign = true; + boolean suppressErrors; + public final LinkedList frameStack = new LinkedList(); + public CompletionState completionState; + + private boolean caseSensitive; + public BracePair[] braces; + public boolean altMode; + + private int lastExpectedVariantOffset = -1; + public MyList variants = new MyList(500); + public MyList unexpected = new MyList(10); + + final LimitedPool VARIANTS = new LimitedPool(1000, new LimitedPool.ObjectFactory() { + public Variant create() { + return new Variant(); + } + + public void cleanup(final Variant o) { + } + }); + final LimitedPool FRAMES = new LimitedPool(100, new LimitedPool.ObjectFactory() { + public Frame create() { + return new Frame(); + } + + public void cleanup(final Frame o) { + } + }); + + public static ErrorState get(PsiBuilder builder) { + return ((Builder)builder).state; + } + + private static void initState(IElementType root, PsiBuilder builder, ErrorState state) { + PsiFile file = builder.getUserDataUnprotected(FileContextUtil.CONTAINING_FILE_KEY); + state.completionState = file == null? null: file.getUserData(COMPLETION_STATE_KEY); + Language language = file == null? root.getLanguage() : file.getLanguage(); + state.caseSensitive = language.isCaseSensitive(); + PairedBraceMatcher matcher = LanguageBraceMatching.INSTANCE.forLanguage(language); + state.braces = matcher == null ? null : matcher.getPairs(); + if (state.braces != null && state.braces.length == 0) state.braces = null; + } + + public String getExpectedText(PsiBuilder builder_) { + int offset = builder_.getCurrentOffset(); + StringBuilder sb = new StringBuilder(); + if (addExpected(sb, offset, true)) { + sb.append(" expected, "); + } + else if (addExpected(sb, offset, false)) sb.append(" unexpected, "); + return sb.toString(); + } + + private static final int MAX_VARIANTS_TO_DISPLAY = Integer.MAX_VALUE; + private boolean addExpected(StringBuilder sb, int offset, boolean expected) { + MyList list = expected ? variants : unexpected; + String[] strings = new String[list.size()]; + long[] hashes = new long[strings.length]; + Arrays.fill(strings, ""); + int count = 0; + loop: for (Variant variant : list) { + if (offset == variant.offset) { + String text = variant.object.toString(); + long hash = StringHash.calc(text); + for (int i=0; i 0) { + if (count > MAX_VARIANTS_TO_DISPLAY) { + sb.append(" and ..."); + break; + } + else { + sb.append(", "); + } + } + char c = s.charAt(0); + String displayText = c == '<' || StringUtil.isJavaIdentifierStart(c) ? s : '\'' + s + '\''; + sb.append(displayText); + } + if (count > 1 && count < MAX_VARIANTS_TO_DISPLAY) { + int idx = sb.lastIndexOf(", "); + sb.replace(idx, idx + 1, " or"); + } + return count > 0; + } + + public void clearVariants(boolean expected, int start) { + MyList list = expected? variants : unexpected; + for (int i = start, len = list.size(); i < len; i ++) { + VARIANTS.recycle(list.get(i)); + } + list.setSize(start); + } + } + + public static class Frame { + public int offset; + public int level; + public String section; + public String name; + public int variantCount; + public int errorReportedAt; + + public Frame() { + } + + public Frame init(int offset, int level, String section, String name, int variantCount) { + this.offset = offset; + this.level = level; + this.section = section; + this.name = name; + this.variantCount = variantCount; + this.errorReportedAt = -1; + return this; + } + + @Override + public String toString() { + return "<"+offset+", "+section+", "+level+">"; + } + } + + + public static class Variant { + int offset; + Object object; + + public Variant init(int offset, Object text) { + this.offset = offset; + this.object = text; + return this; + } + + @Override + public String toString() { + return "<" + offset + ", " + object + ">"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Variant variant = (Variant)o; + + if (offset != variant.offset) return false; + if (!this.object.equals(variant.object)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = offset; + result = 31 * result + object.hashCode(); + return result; + } + } + + @Nullable + private static IElementType getClosingBracket(ErrorState state, IElementType type) { + if (state.braces == null) return null; + for (BracePair pair : state.braces) { + if (type == pair.getLeftBraceType()) return pair.getRightBraceType(); + } + return null; + } + + + private static final int MAX_CHILDREN_IN_TREE = 10; + public static boolean parseAsTree(ErrorState state, final PsiBuilder builder_, int level, final IElementType chunkType, + boolean checkBraces, final Parser parser, final Parser eatMoreCondition) { + final LinkedList> parenList = new LinkedList>(); + final LinkedList> siblingList = new LinkedList>(); + PsiBuilder.Marker marker = null; + + final Runnable checkSiblingsRunnable = new Runnable() { + public void run() { + main: + while (!siblingList.isEmpty()) { + final Pair parenPair = parenList.peek(); + final int rating = siblingList.getFirst().second; + int count = 0; + for (Pair pair : siblingList) { + if (pair.second != rating || parenPair != null && pair.first == parenPair.second) break main; + if (++count >= MAX_CHILDREN_IN_TREE) { + final PsiBuilder.Marker parentMarker = pair.first.precede(); + while (count-- > 0) { + siblingList.removeFirst(); + } + parentMarker.done(chunkType); + siblingList.addFirst(Pair.create(parentMarker, rating + 1)); + continue main; + } + } + break; + } + } + }; + boolean checkParens = state.braces != null && checkBraces; + int totalCount = 0; + int tokenCount = 0; + if (checkParens && builder_.rawLookup(-1) == state.braces[0].getLeftBraceType()) { + LighterASTNode doneMarker = builder_.getLatestDoneMarker(); + if (doneMarker != null && doneMarker.getStartOffset() == builder_.rawTokenTypeStart(-1) && doneMarker.getTokenType() == TokenType.ERROR_ELEMENT) { + parenList.add(Pair.create(((PsiBuilder.Marker)doneMarker).precede(), (PsiBuilder.Marker)null)); + } + } + while (true) { + final IElementType tokenType = builder_.getTokenType(); + if (checkParens && (tokenType == state.braces[0].getLeftBraceType() || tokenType == state.braces[0].getRightBraceType() && !parenList.isEmpty())) { + if (marker != null) { + marker.done(chunkType); + siblingList.addFirst(Pair.create(marker, 1)); + marker = null; + tokenCount = 0; + } + if (tokenType == state.braces[0].getLeftBraceType()) { + final Pair prev = siblingList.peek(); + parenList.addFirst(Pair.create(builder_.mark(), prev == null ? null : prev.first)); + } + checkSiblingsRunnable.run(); + builder_.advanceLexer(); + if (tokenType == state.braces[0].getRightBraceType()) { + final Pair pair = parenList.removeFirst(); + pair.first.done(chunkType); + // drop all markers inside parens + while (!siblingList.isEmpty() && siblingList.getFirst().first != pair.second) { + siblingList.removeFirst(); + } + siblingList.addFirst(Pair.create(pair.first, 1)); + checkSiblingsRunnable.run(); + } + } + else { + if (marker == null) { + marker = builder_.mark(); + } + final boolean result = (state.altMode && !parenList.isEmpty() || eatMoreCondition.parse(builder_, level + 1)) && parser.parse(builder_, level + 1); + if (result) { + tokenCount++; + totalCount++; + } + if (!result) { + break; + } + } + + if (tokenCount >= MAX_CHILDREN_IN_TREE && marker != null) { + marker.done(chunkType); + siblingList.addFirst(Pair.create(marker, 1)); + checkSiblingsRunnable.run(); + marker = null; + tokenCount = 0; + } + } + if (marker != null) { + marker.drop(); + } + for (Pair pair : parenList) { + pair.first.drop(); + } + return totalCount != 0; + } + + private static class DummyBlockElementType extends IElementType implements ICompositeElementType{ + DummyBlockElementType() { + super("DUMMY_BLOCK", Language.ANY); + } + + @NotNull + @Override + public ASTNode createCompositeNode() { + return new DummyBlock(); + } + } + + public static class DummyBlock extends CompositePsiElement { + DummyBlock() { + super(DUMMY_BLOCK); + } + + @Override + public PsiReference[] getReferences() { + return PsiReference.EMPTY_ARRAY; + } + + @Override + public boolean canNavigateToSource() { + return false; + } + + @Override + public boolean canNavigate() { + return false; + } + + @NotNull + @Override + public Language getLanguage() { + return getParent().getLanguage(); + } + } + + protected static class MyList extends ArrayList { + public MyList(int initialCapacity) { + super(initialCapacity); + } + + protected void setSize(int fromIndex) { + super.removeRange(fromIndex, size()); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/paths/PsiDynaReference.java b/platform/lang-impl/src/com/intellij/openapi/paths/PsiDynaReference.java index ff6e12637e68..35cfc426c60c 100644 --- a/platform/lang-impl/src/com/intellij/openapi/paths/PsiDynaReference.java +++ b/platform/lang-impl/src/com/intellij/openapi/paths/PsiDynaReference.java @@ -207,6 +207,7 @@ public class PsiDynaReference extends PsiReferenceBase } } + @NotNull @Override @SuppressWarnings({"UnresolvedPropertyKey"}) public String getUnresolvedMessagePattern() { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java index 861e6cf3e3a7..338563f3104d 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java @@ -553,6 +553,7 @@ public class FileReference implements FileReferenceOwner, PsiPolyVariantReferenc return myIndex; } + @NotNull @Override public String getUnresolvedMessagePattern() { return LangBundle.message("error.cannot.resolve") diff --git a/platform/platform-api/src/com/intellij/ide/BrowserSettingsProvider.java b/platform/platform-api/src/com/intellij/ide/BrowserSettingsProvider.java index 01f628bb0e4f..63576284ba03 100644 --- a/platform/platform-api/src/com/intellij/ide/BrowserSettingsProvider.java +++ b/platform/platform-api/src/com/intellij/ide/BrowserSettingsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,6 @@ import com.intellij.openapi.options.UnnamedConfigurable; * @author spleaner */ public abstract class BrowserSettingsProvider implements UnnamedConfigurable { - public void disposeUIResources() { - } - - public void applySettingsFromWindowsRegistry() {} + @Override + public void disposeUIResources() { } } diff --git a/platform/platform-api/src/org/jetbrains/ide/HttpRequestHandler.java b/platform/platform-api/src/org/jetbrains/ide/HttpRequestHandler.java index 62082dcc684a..4745524a01b9 100644 --- a/platform/platform-api/src/org/jetbrains/ide/HttpRequestHandler.java +++ b/platform/platform-api/src/org/jetbrains/ide/HttpRequestHandler.java @@ -23,13 +23,10 @@ import org.jboss.netty.handler.codec.http.QueryStringDecoder; import java.io.IOException; public abstract class HttpRequestHandler { - public boolean isSupported(HttpMethod method) { - return method == HttpMethod.GET; + public boolean isSupported(HttpRequest request) { + return request.getMethod() == HttpMethod.GET; } public abstract boolean process(QueryStringDecoder urlDecoder, HttpRequest request, ChannelHandlerContext context) throws IOException; - - public void serverStopping() { - } } diff --git a/platform/platform-api/src/org/jetbrains/ide/WebServerManager.java b/platform/platform-api/src/org/jetbrains/ide/WebServerManager.java index a2fa6e0802fb..c33154ef57bb 100644 --- a/platform/platform-api/src/org/jetbrains/ide/WebServerManager.java +++ b/platform/platform-api/src/org/jetbrains/ide/WebServerManager.java @@ -15,8 +15,10 @@ */ package org.jetbrains.ide; +import com.intellij.openapi.Disposable; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.extensions.ExtensionPointName; +import org.jetbrains.annotations.Nullable; public abstract class WebServerManager { // Your handler will be instantiated on first user request @@ -29,4 +31,7 @@ public abstract class WebServerManager { public abstract int getPort(); public abstract WebServerManager waitForStart(); + + @Nullable + public abstract Disposable getServerDisposable(); } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/BrowserSettingsPanel.java b/platform/platform-impl/src/com/intellij/ide/BrowserSettingsPanel.java index 54a77de5aa90..0a66235679e3 100644 --- a/platform/platform-impl/src/com/intellij/ide/BrowserSettingsPanel.java +++ b/platform/platform-impl/src/com/intellij/ide/BrowserSettingsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -111,21 +111,6 @@ public class BrowserSettingsPanel extends JPanel { for (BrowserSettingsProvider settingsProvider : mySettingsProviders) { outerPanel.add(settingsProvider.createComponent()); } - if (SystemInfo.isWindows) { - JPanel wrapperPanel = new JPanel(new BorderLayout()); - JButton registryButton = new JButton("Retrieve settings from Windows registry"); - registryButton.setMnemonic('W'); - registryButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - for (BrowserSettingsProvider settingsProvider : mySettingsProviders) { - settingsProvider.applySettingsFromWindowsRegistry(); - } - } - }); - wrapperPanel.add(registryButton, BorderLayout.EAST); - outerPanel.add(wrapperPanel); - } add(outerPanel, BorderLayout.NORTH); } diff --git a/platform/platform-impl/src/com/intellij/ide/XmlRpcServerImpl.java b/platform/platform-impl/src/com/intellij/ide/XmlRpcServerImpl.java index dbf50cf1ee76..eaf066b3bea0 100644 --- a/platform/platform-impl/src/com/intellij/ide/XmlRpcServerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/XmlRpcServerImpl.java @@ -79,8 +79,8 @@ public class XmlRpcServerImpl implements XmlRpcServer { static final class XmlRpcRequestHandler extends HttpRequestHandler { @Override - public boolean isSupported(HttpMethod method) { - return method == HttpMethod.POST || method == HttpMethod.OPTIONS; + public boolean isSupported(HttpRequest request) { + return request.getMethod() == HttpMethod.POST || request.getMethod() == HttpMethod.OPTIONS; } @Override @@ -103,7 +103,7 @@ public class XmlRpcServerImpl implements XmlRpcServer { } private boolean process(QueryStringDecoder urlDecoder, HttpRequest request, ChannelHandlerContext context) throws IOException { - if (!(urlDecoder.getPath().isEmpty() || urlDecoder.getPath().equalsIgnoreCase("/RPC2"))) { + if (!isXmlRpcRequest(urlDecoder.getPath())) { return false; } @@ -138,6 +138,10 @@ public class XmlRpcServerImpl implements XmlRpcServer { return false; } + private static boolean isXmlRpcRequest(String path) { + return path.isEmpty() || (path.length() == 1 && path.charAt(0) == '/') || path.equalsIgnoreCase("/RPC2"); + } + private static class XmlRpcHandlerMappingImpl implements XmlRpcHandlerMapping { protected final THashMap handlers = new THashMap(); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java index 9f158aa2634d..7c2bc8230b4d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java @@ -28,6 +28,7 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.UniqueNameBuilder; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.ClickListener; import com.intellij.ui.ListUtil; import com.intellij.ui.components.JBList; @@ -95,17 +96,24 @@ public class RecentProjectPanel extends JPanel { ActionListener deleteAction = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - ReopenProjectAction selection = (ReopenProjectAction)myList.getSelectedValue(); + Object[] selection = myList.getSelectedValues(); - if (selection != null) { + if (selection != null && selection.length > 0) { final int rc = Messages.showOkCancelDialog(RecentProjectPanel.this, - "Remove '" + selection.getTemplatePresentation().getText() + + "Remove '" + StringUtil.join(selection, new Function() { + @Override + public String fun(Object action) { + return ((ReopenProjectAction)action).getTemplatePresentation().getText(); + } + }, "'\n'") + "' from recent projects list?", "Remove Recent Project", Messages.getQuestionIcon()); if (rc == 0) { final RecentProjectsManagerBase manager = RecentProjectsManagerBase.getInstance(); - manager.removePath(selection.getProjectPath()); + for (Object projectAction : selection) { + manager.removePath(((ReopenProjectAction)projectAction).getProjectPath()); + } ListUtil.removeSelectedItems(myList); } } diff --git a/platform/platform-impl/src/org/jetbrains/ide/WebServerManagerImpl.java b/platform/platform-impl/src/org/jetbrains/ide/WebServerManagerImpl.java index ca859a3a762b..854374c04033 100644 --- a/platform/platform-impl/src/org/jetbrains/ide/WebServerManagerImpl.java +++ b/platform/platform-impl/src/org/jetbrains/ide/WebServerManagerImpl.java @@ -12,6 +12,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupActivity; +import com.intellij.openapi.util.Disposer; import org.jboss.netty.channel.ChannelException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; @@ -21,7 +22,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; -class WebServerManagerImpl extends WebServerManager implements Disposable { +class WebServerManagerImpl extends WebServerManager { private static final Logger LOG = Logger.getInstance(WebServerManager.class); @NonNls @@ -102,6 +103,7 @@ class WebServerManagerImpl extends WebServerManager implements Disposable { return; } + Disposer.register(ApplicationManager.getApplication(), server); detectedPortNumber = server.start(getDefaultPort(), PORTS_COUNT, true); if (detectedPortNumber == -1) { LOG.info("web server cannot be started, cannot bind to port"); @@ -114,10 +116,8 @@ class WebServerManagerImpl extends WebServerManager implements Disposable { } @Override - public void dispose() { - if (started.get() && server != null) { - server.stop(); - LOG.info("web server stopped"); - } + @Nullable + public Disposable getServerDisposable() { + return server; } } \ No newline at end of file diff --git a/platform/platform-impl/src/org/jetbrains/io/WebServer.java b/platform/platform-impl/src/org/jetbrains/io/WebServer.java index d858eb86688e..90d89cbd1ca0 100644 --- a/platform/platform-impl/src/org/jetbrains/io/WebServer.java +++ b/platform/platform-impl/src/org/jetbrains/io/WebServer.java @@ -15,6 +15,7 @@ */ package org.jetbrains.io; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; @@ -46,7 +47,7 @@ import static org.jboss.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK; import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1; -public class WebServer { +public class WebServer implements Disposable { private static final String START_TIME_PATH = "/startTime"; private final ChannelGroup openChannels = new DefaultChannelGroup("web-server"); @@ -247,25 +248,15 @@ public class WebServer { } } - public void stop() { + @Override + public void dispose() { try { - for (HttpRequestHandler handler : WebServerManager.EP_NAME.getExtensions()) { - try { - handler.serverStopping(); - } - catch (Exception e) { - LOG.error(e); - } - } + openChannels.close().awaitUninterruptibly(); } finally { - try { - openChannels.close().awaitUninterruptibly(); - } - finally { - channelFactory.releaseExternalResources(); - } + channelFactory.releaseExternalResources(); } + LOG.info("web server stopped"); } public static void replaceDefaultHandler(@NotNull ChannelHandlerContext context, @NotNull SimpleChannelUpstreamHandler messageChannelHandler) { @@ -302,6 +293,7 @@ public class WebServer { public void messageReceived(ChannelHandlerContext context, MessageEvent event) throws Exception { if (!(event.getMessage() instanceof HttpRequest)) { context.sendUpstream(event); + return; } HttpRequest request = (HttpRequest)event.getMessage(); @@ -320,7 +312,7 @@ public class WebServer { if (connectedHandler == null) { for (HttpRequestHandler handler : WebServerManager.EP_NAME.getExtensions()) { try { - if (handler.isSupported(request.getMethod()) && handler.process(urlDecoder, request, context)) { + if (handler.isSupported(request) && handler.process(urlDecoder, request, context)) { if (context.getAttachment() == null) { context.setAttachment(handler); } @@ -332,7 +324,7 @@ public class WebServer { } } } - else if (connectedHandler.isSupported(request.getMethod())) { + else if (connectedHandler.isSupported(request)) { connectedHandler.process(urlDecoder, request, context); return; } diff --git a/platform/platform-resources-en/src/messages/XmlBundle.properties b/platform/platform-resources-en/src/messages/XmlBundle.properties index e581c3658a20..04ed0e5f9dbe 100644 --- a/platform/platform-resources-en/src/messages/XmlBundle.properties +++ b/platform/platform-resources-en/src/messages/XmlBundle.properties @@ -248,4 +248,6 @@ zen.coding.incorrect.abbreviation.error=Incorrect abbreviation title.cannot.create.html.file=Cannot create HTML file new.html.file.action=HTML File new.html.file.action.description=Creates new HTML file -html5.outline.mode=HTML5 Outline \ No newline at end of file +html5.outline.mode=HTML5 Outline + +read.win.registry=Retrieve settings from &Windows registry diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 2188c29f1126..df03c22ed87c 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -1,589 +1,594 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - + - + - - + + - - - - - - - + + + + + + + - + - + - - - + + + - + - + - + - + - - - + + + - - - + + + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - - + + - + - - + + - + - + - - + + - + + + + + - - diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 434bfa988305..060290a71f2e 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -1,809 +1,824 @@ - - - + + + + - + - + - + - - + + - + - + - + - - - + + + - + - - - + + + - + - + - + - + - + - - - - - - + + + + + + - - - - + + + + - + - + - + - + - + - + - + - - + + - + - + - + - - + + - - + + - - - - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - - - - - - - - - - + + + + + + + + + + - + - + - + - + - - - - + + + + - + - - - - + + + + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + com.intellij.codeInsight.intention.impl.EditFoldingOptionsAction + + + com.intellij.codeInsight.intention.impl.QuickEditAction + Language Injection + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - com.intellij.codeInsight.intention.impl.EditFoldingOptionsAction - - - com.intellij.codeInsight.intention.impl.QuickEditAction - Language Injection - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + + - + - + - + - - - - + - + - + + + + - + - + - + - - + - + - + + - - + + + + + + + + + + + + + + - - - - - - diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 3926f1a73f93..4cdac7626907 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -1,155 +1,181 @@ - - - + + + + - + - + - + - + + + - + + + - + - + - + - + - + + + - + - - - + + + - - + + + - + - - - + + - - + - - - + + + - - + + - + - - + + + - + + + - - + - - - - + + + - - + + - - + - - - + + - + + + + - - - - + + - - - - + + + + - + + + - - - + + - + - - - + + + + - + + + + - - - + - - + + + - + - + - - - - + - + - - + + + - + + - - + - + - - + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index ad4b9242c132..78ea7f3ed091 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -1,296 +1,298 @@ - - - - + + + + + - - + + - + - + - + - - - - + + + + - - + + - + - - + + - + - + - - - - - + + + + + - + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - + + + + + + - + - - - - - + + + + + - + - + - - - - + + + + - + - - - + + + - + - + - + - + - + - + - + - + - - + + - - + + - - - + + + - - + + - - + + - - + + - - - - - + + + + + - - + - + - + - + - - + + - - - - - - + + + + + + - - - + + + - - + + - - - - - - - + + + + + + + - + - - - + + + - + - - - - + + + + - + - - - + + + - - + + - + - - + + - + - - - - + + + + - - + + + diff --git a/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml b/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml index 6c318b5e79ef..9057536b9935 100644 --- a/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml +++ b/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml @@ -11,15 +11,15 @@ - - - + + + - - - + + + @@ -90,7 +90,7 @@ - + diff --git a/platform/platform-resources/src/META-INF/PlatformPlugin.xml b/platform/platform-resources/src/META-INF/PlatformPlugin.xml index 38ea712e97ff..b7b3395aaa03 100644 --- a/platform/platform-resources/src/META-INF/PlatformPlugin.xml +++ b/platform/platform-resources/src/META-INF/PlatformPlugin.xml @@ -6,13 +6,13 @@ - - + + - - + + diff --git a/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml b/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml index 8541a4543a4b..aff52957aed9 100644 --- a/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml @@ -1,52 +1,54 @@ - - - - - + + + + + + - + - + - + - + - + - + - + - - - - - + + + - - - - - + + + + + + + - \ No newline at end of file + + diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml index bee6fb41085e..5b77969e431d 100644 --- a/platform/platform-resources/src/META-INF/VcsExtensions.xml +++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml @@ -1,40 +1,43 @@ - - + + + - - - - - - - + + + + + + + - + - + - - + + - - - + + + - + - - - - + + + + + + + + + + - - - - diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index f8aa0b319f3e..5bf0b9d30736 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -375,7 +375,7 @@ - + diff --git a/platform/platform-resources/src/META-INF/xdebugger.xml b/platform/platform-resources/src/META-INF/xdebugger.xml index e46191a84a1c..3a47c11d583f 100644 --- a/platform/platform-resources/src/META-INF/xdebugger.xml +++ b/platform/platform-resources/src/META-INF/xdebugger.xml @@ -1,4 +1,4 @@ - + com.intellij.xdebugger.XDebuggerManager @@ -37,4 +37,4 @@ - + diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index bcf5dba4e160..2ffc651befb7 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -25,10 +25,7 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.impl.StartMarkAction; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.JDOMExternalizable; -import com.intellij.openapi.util.JDOMUtil; -import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; @@ -40,6 +37,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.refactoring.rename.inplace.InplaceRefactoring; +import com.intellij.rt.execution.junit.FileComparisonFailure; import com.intellij.testFramework.exceptionCases.AbstractExceptionCase; import com.intellij.util.Consumer; import com.intellij.util.Function; @@ -621,7 +619,7 @@ public abstract class UsefulTestCase extends TestCase { return testName.replaceAll("_.*", ""); } - protected static void assertSameLinesWithFile(final String filePath, final String actualText) { + protected static void assertSameLinesWithFile(String filePath, String actualText) { String fileText; try { if (OVERWRITE_TESTDATA) { @@ -633,7 +631,11 @@ public abstract class UsefulTestCase extends TestCase { catch (IOException e) { throw new RuntimeException(e); } - assertSameLines(fileText, actualText); + String expected = StringUtil.convertLineSeparators(fileText.trim()); + String actual = StringUtil.convertLineSeparators(actualText.trim()); + if (!Comparing.equal(expected, actual)) { + throw new FileComparisonFailure(null, expected, actual, filePath); + } } public static void clearFields(final Object test) throws IllegalAccessException { diff --git a/platform/util-rt/src/com/intellij/BundleBase.java b/platform/util-rt/src/com/intellij/BundleBase.java index 8b230fe0e160..75c72d8b87ba 100644 --- a/platform/util-rt/src/com/intellij/BundleBase.java +++ b/platform/util-rt/src/com/intellij/BundleBase.java @@ -58,7 +58,8 @@ public abstract class BundleBase { return format(value, params); } - public static String format(String value, Object... params) { + @NotNull + public static String format(@NotNull String value, @NotNull Object... params) { if (params.length > 0 && value.indexOf('{') >= 0) { return MessageFormat.format(value, params); } diff --git a/platform/util/src/com/intellij/util/ObjectUtils.java b/platform/util/src/com/intellij/util/ObjectUtils.java index fe917abfad43..8e5e52d94bd4 100644 --- a/platform/util/src/com/intellij/util/ObjectUtils.java +++ b/platform/util/src/com/intellij/util/ObjectUtils.java @@ -15,6 +15,7 @@ */ package com.intellij.util; +import com.intellij.openapi.util.Condition; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -56,8 +57,8 @@ public class ObjectUtils { } @Nullable - public static T nullizeIfSubtype(@Nullable T obj, @NotNull Class clazz) { - if (clazz.isInstance(obj)) { + public static T nullizeByCondition(@Nullable final T obj, @NotNull final Condition condition) { + if (condition.value(obj)) { return null; } return obj; diff --git a/platform/util/src/com/intellij/util/xmlb/JDOMXIncluder.java b/platform/util/src/com/intellij/util/xmlb/JDOMXIncluder.java index 1936d7e00bb1..8a764574f686 100644 --- a/platform/util/src/com/intellij/util/xmlb/JDOMXIncluder.java +++ b/platform/util/src/com/intellij/util/xmlb/JDOMXIncluder.java @@ -257,8 +257,8 @@ public class JDOMXIncluder { //xpointer($1) @NonNls public static Pattern XPOINTER_PATTERN = Pattern.compile("xpointer\\((.*)\\)"); - // /$1/* - public static Pattern CHILDREN_PATTERN = Pattern.compile("\\/(.*)\\/\\*"); + // /$1(/$2)?/* + public static Pattern CHILDREN_PATTERN = Pattern.compile("/([^/]*)(/[^/]*)?/\\*"); @Nullable private static List extractNeededChildren(final Element element, List remoteElements) { @@ -283,8 +283,13 @@ public class JDOMXIncluder { Element e = (Element)remoteElements.get(0); - if (e.getName().equals(rootTagName)) return - new ArrayList(e.getContent()); + if (e.getName().equals(rootTagName)) { + String subTagName = matcher.group(2); + if (subTagName != null) { + e = e.getChild(subTagName.substring(1)); // cut off the slash + } + return new ArrayList(e.getContent()); + } else return Collections.emptyList(); } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java index 761a5ed58279..dfcd908d8e77 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,26 +28,22 @@ public class NoopMethodInAbstractClassInspection extends BaseInspection { @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message( - "noop.method.in.abstract.class.display.name"); + return InspectionGadgetsBundle.message("noop.method.in.abstract.class.display.name"); } @NotNull protected String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "noop.method.in.abstract.class.problem.descriptor"); + return InspectionGadgetsBundle.message("noop.method.in.abstract.class.problem.descriptor"); } public BaseInspectionVisitor buildVisitor() { return new NoopMethodInAbstractClassVisitor(); } - private static class NoopMethodInAbstractClassVisitor - extends BaseInspectionVisitor { + private static class NoopMethodInAbstractClassVisitor extends BaseInspectionVisitor { @Override public void visitMethod(@NotNull PsiMethod method) { - //no call to super, so we don't drill into anonymous classes if (method.isConstructor()) { return; } @@ -55,14 +51,13 @@ public class NoopMethodInAbstractClassInspection extends BaseInspection { if (containingClass == null) { return; } - if (containingClass.isInterface() || - containingClass.isAnnotationType()) { + if (containingClass.isInterface() || containingClass.isAnnotationType()) { return; } if (!containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) { return; } - if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + if (method.hasModifierProperty(PsiModifier.ABSTRACT) || method.hasModifierProperty(PsiModifier.NATIVE)) { return; } if (!MethodUtils.isEmpty(method)) { diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/noop_method_in_abstract_class/NoopMethodInAbstractClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/noop_method_in_abstract_class/NoopMethodInAbstractClass.java new file mode 100644 index 000000000000..214152da741d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/noop_method_in_abstract_class/NoopMethodInAbstractClass.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.classlayout.noop_method_in_abstract_class; + +abstract class NoopMethodInAbstractClass { + + void foo() {} + + native int bar(); +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/noop_method_in_abstract_class/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/noop_method_in_abstract_class/expected.xml new file mode 100644 index 000000000000..79ebd7255099 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/noop_method_in_abstract_class/expected.xml @@ -0,0 +1,9 @@ + + + + NoopMethodInAbstractClass.java + 5 + No-op method in abstract class + No-op Method <code>foo()</code> should be made abstract #loc + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspectionTest.java new file mode 100644 index 000000000000..a7737a07f77c --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspectionTest.java @@ -0,0 +1,10 @@ +package com.siyeh.ig.classlayout; + +import com.siyeh.ig.IGInspectionTestCase; + +public class NoopMethodInAbstractClassInspectionTest extends IGInspectionTestCase { + + public void test() throws Exception { + doTest("com/siyeh/igtest/classlayout/noop_method_in_abstract_class", new NoopMethodInAbstractClassInspection()); + } +} \ No newline at end of file diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileReference.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileReference.java index b79dc71de44e..ad45851ff043 100644 --- a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileReference.java +++ b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileReference.java @@ -47,6 +47,7 @@ public class AntDomFileReference extends FileReference implements AntDomReferenc return (AntDomFileReferenceSet)super.getFileReferenceSet(); } + @NotNull public String getUnresolvedMessagePattern() { return AntBundle.message("file.doesnt.exist", getCanonicalRepresentationText()); } diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index 3ef7a655605c..8413b924237f 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -84,7 +84,7 @@ - + diff --git a/plugins/devkit/src/dom/Component.java b/plugins/devkit/src/dom/Component.java index ddb9cec7250f..aa5936b30a3c 100644 --- a/plugins/devkit/src/dom/Component.java +++ b/plugins/devkit/src/dom/Component.java @@ -44,6 +44,7 @@ public interface Component extends DomElement { @NotNull @Convert(PluginPsiClassConverter.class) + @ExtendClass(allowEmpty=true) GenericDomValue getHeadlessImplementationClass(); @NotNull diff --git a/plugins/devkit/src/dom/ExtensionPoint.java b/plugins/devkit/src/dom/ExtensionPoint.java index 1c5662e63108..c05fbf8b8c27 100644 --- a/plugins/devkit/src/dom/ExtensionPoint.java +++ b/plugins/devkit/src/dom/ExtensionPoint.java @@ -21,6 +21,8 @@ import com.intellij.util.xml.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.devkit.dom.impl.PluginPsiClassConverter; +import java.util.List; + /** * @author mike */ @@ -50,4 +52,8 @@ public interface ExtensionPoint extends DomElement { @NotNull GenericAttributeValue getArea(); + + @NotNull + @SubTagList("with") + List getWithElements(); } diff --git a/plugins/devkit/src/dom/With.java b/plugins/devkit/src/dom/With.java new file mode 100644 index 000000000000..f5054ce100f2 --- /dev/null +++ b/plugins/devkit/src/dom/With.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2013 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.idea.devkit.dom; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiField; +import com.intellij.util.xml.Attribute; +import com.intellij.util.xml.Convert; +import com.intellij.util.xml.DomElement; +import com.intellij.util.xml.GenericAttributeValue; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.devkit.dom.impl.PluginFieldNameConverter; +import org.jetbrains.idea.devkit.dom.impl.PluginPsiClassConverter; + +/** + * @author yole + */ +public interface With extends DomElement { + @NotNull + @Attribute("attribute") + @Convert(PluginFieldNameConverter.class) + GenericAttributeValue getAttribute(); + + + @NotNull + @Attribute("implements") + @Convert(PluginPsiClassConverter.class) + GenericAttributeValue getImplements(); +} diff --git a/plugins/devkit/src/dom/impl/PluginFieldNameConverter.java b/plugins/devkit/src/dom/impl/PluginFieldNameConverter.java new file mode 100644 index 000000000000..aebdd1e1d88e --- /dev/null +++ b/plugins/devkit/src/dom/impl/PluginFieldNameConverter.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2013 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.idea.devkit.dom.impl; + +import com.intellij.psi.*; +import com.intellij.util.xml.ConvertContext; +import com.intellij.util.xml.ResolvingConverter; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.devkit.dom.ExtensionPoint; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author yole + */ +public class PluginFieldNameConverter extends ResolvingConverter { + @NotNull + @Override + public Collection getVariants(ConvertContext context) { + PsiClass aClass = getEPBeanClass(context); + if (aClass == null) return Collections.emptyList(); + List result = new ArrayList(); + for (PsiField field : aClass.getAllFields()) { + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + PsiType type = field.getType(); + if (type instanceof PsiClassType) { + PsiClass resolved = ((PsiClassType)type).resolve(); + if (resolved != null && CommonClassNames.JAVA_LANG_STRING.equals(resolved.getQualifiedName())) { + result.add(field); + } + } + } + } + return result; + } + + @Nullable + @Override + public PsiField fromString(@Nullable @NonNls String s, ConvertContext context) { + PsiClass value = getEPBeanClass(context); + if (value == null) return null; + return value.findFieldByName(s, true); + } + + @Nullable + @Override + public String toString(@Nullable PsiField field, ConvertContext context) { + return field == null ? null : field.getName(); + } + + @Nullable + private static PsiClass getEPBeanClass(ConvertContext context) { + ExtensionPoint ep = context.getInvocationElement().getParentOfType(ExtensionPoint.class, true); + if (ep == null) return null; + PsiClass value = ep.getBeanClass().getValue(); + if (value == null) return null; + return value; + } +} diff --git a/plugins/devkit/src/inspections/quickfix/RegisterExtensionFix.java b/plugins/devkit/src/inspections/quickfix/RegisterExtensionFix.java new file mode 100644 index 000000000000..f233f6ea4821 --- /dev/null +++ b/plugins/devkit/src/inspections/quickfix/RegisterExtensionFix.java @@ -0,0 +1,92 @@ +/* + * Copyright 2000-2013 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.idea.devkit.inspections.quickfix; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.util.Consumer; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.PsiNavigateUtil; +import com.intellij.util.xml.DomFileElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.devkit.dom.Extension; +import org.jetbrains.idea.devkit.dom.Extensions; +import org.jetbrains.idea.devkit.dom.IdeaPlugin; + +/** + * @author yole + */ +public class RegisterExtensionFix implements IntentionAction { + private final PsiClass myExtensionClass; + private final String myEPName; + + public RegisterExtensionFix(PsiClass extensionClass, String epName) { + myExtensionClass = extensionClass; + myEPName = epName; + } + + @NotNull + @Override + public String getText() { + return "Register extension"; + } + + @NotNull + @Override + public String getFamilyName() { + return getText(); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return true; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + RegisterInspectionFix.choosePluginDescriptor(project, editor, file, new Consumer>() { + @Override + public void consume(DomFileElement element) { + doFix(element); + } + }); + } + + private void doFix(final DomFileElement element) { + Extension extension = new WriteCommandAction(element.getFile().getProject(), element.getFile()) { + @Override + protected void run(Result result) throws Throwable { + Extensions extensions = RegisterInspectionFix.getExtension(element.getRootElement(), myEPName); + Extension extension = extensions.addExtension(myEPName); + XmlTag tag = extension.getXmlTag(); + tag.setAttribute("implementation", myExtensionClass.getQualifiedName()); + result.setResult(extension); + } + }.execute().throwException().getResultObject(); + PsiNavigateUtil.navigate(extension.getXmlTag()); + } + + @Override + public boolean startInWriteAction() { + return false; + } +} diff --git a/plugins/devkit/src/inspections/quickfix/RegisterExtensionFixProvider.java b/plugins/devkit/src/inspections/quickfix/RegisterExtensionFixProvider.java new file mode 100644 index 000000000000..21d0e05c4e9c --- /dev/null +++ b/plugins/devkit/src/inspections/quickfix/RegisterExtensionFixProvider.java @@ -0,0 +1,101 @@ +/* + * 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 org.jetbrains.idea.devkit.inspections.quickfix; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.GlobalInspectionTool; +import com.intellij.codeInspection.InspectionEP; +import com.intellij.codeInspection.LocalInspectionEP; +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.reference.UnusedDeclarationFixProvider; +import com.intellij.ide.highlighter.XmlFileType; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.ProjectScope; +import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Avdeev + * Date: 1/19/12 + */ +public class RegisterExtensionFixProvider implements UnusedDeclarationFixProvider { + + @NotNull + @Override + public IntentionAction[] getQuickFixes(PsiElement element) { + if (!(element instanceof PsiIdentifier)) return IntentionAction.EMPTY_ARRAY; + PsiElement parent = element.getParent(); + if (!(parent instanceof PsiClass)) return IntentionAction.EMPTY_ARRAY; + PsiClass parentClass = (PsiClass)parent; + if (InheritanceUtil.isInheritor(parentClass, LocalInspectionTool.class.getName())) { + return new IntentionAction[] { new RegisterInspectionFix(parentClass, LocalInspectionEP.LOCAL_INSPECTION) }; + } + if (InheritanceUtil.isInheritor(parentClass, GlobalInspectionTool.class.getName())) { + return new IntentionAction[] { new RegisterInspectionFix(parentClass, InspectionEP.GLOBAL_INSPECTION) }; + } + PsiField epField = findEPNameField(parentClass); + if (epField != null) { + String epName = findEPNameForClass(epField.getContainingClass()); + if (epName != null) { + return new IntentionAction[] { new RegisterExtensionFix(parentClass, epName) }; + } + } + return IntentionAction.EMPTY_ARRAY; + } + + private static String findEPNameForClass(PsiClass aClass) { + GlobalSearchScope scope = GlobalSearchScope.getScopeRestrictedByFileTypes(ProjectScope.getAllScope(aClass.getProject()), XmlFileType.INSTANCE); + for (PsiReference reference : ReferencesSearch.search(aClass, scope)) { + XmlTag tag = PsiTreeUtil.getParentOfType(reference.getElement(), XmlTag.class); + if (tag != null && "extensionPoint".equals(tag.getName())) { + String qName = tag.getAttributeValue("qualifiedName"); + if (qName != null) { + return qName; + } + String name = tag.getAttributeValue("name"); + if (name != null) { + return "com.intellij." + name; + } + } + } + return null; + } + + private static PsiField findEPNameField(PsiClass aClass) { + for (PsiField field : aClass.getFields()) { + if (field.getType() instanceof PsiClassType) { + PsiClassType classType = (PsiClassType)field.getType(); + PsiClassType.ClassResolveResult resolved = classType.resolveGenerics(); + PsiClass fieldClass = resolved.getElement(); + if (fieldClass != null && ExtensionPointName.class.getName().equals(fieldClass.getQualifiedName())) { + return field; + } + } + } + for (PsiClass superClass: aClass.getSupers()) { + PsiField epField = findEPNameField(superClass); + if (epField != null) { + return epField; + } + } + return null; + } +} diff --git a/plugins/devkit/src/inspections/quickfix/RegisterInspectionFix.java b/plugins/devkit/src/inspections/quickfix/RegisterInspectionFix.java index b709bf83719d..6eace3d6321f 100644 --- a/plugins/devkit/src/inspections/quickfix/RegisterInspectionFix.java +++ b/plugins/devkit/src/inspections/quickfix/RegisterInspectionFix.java @@ -37,6 +37,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlTag; +import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; import com.intellij.util.PsiNavigateUtil; import com.intellij.util.containers.ContainerUtil; @@ -84,6 +85,16 @@ class RegisterInspectionFix implements IntentionAction { @Override public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { + choosePluginDescriptor(project, editor, file, new Consumer>() { + @Override + public void consume(DomFileElement element) { + doFix(element, project, file); + } + }); + } + + public static void choosePluginDescriptor(final Project project, Editor editor, final PsiFile file, + final Consumer> consumer) { Module module = ModuleUtil.findModuleForPsiElement(file); assert module != null; List> elements = @@ -103,7 +114,7 @@ class RegisterInspectionFix implements IntentionAction { } if (elements.size() == 1) { - doFix(elements.get(0), project, file); + consumer.consume(elements.get(0)); return; } @@ -127,7 +138,7 @@ class RegisterInspectionFix implements IntentionAction { @Override public PopupStep onChosen(DomFileElement selectedValue, boolean finalChoice) { - doFix(selectedValue, project, file); + consumer.consume(selectedValue); return FINAL_CHOICE; } }; @@ -137,12 +148,11 @@ class RegisterInspectionFix implements IntentionAction { private void doFix(DomFileElement selectedValue, final Project project, final PsiFile file) { final IdeaPlugin plugin = selectedValue.getRootElement(); - final List extensionsList = plugin.getExtensions(); Extension extension = new WriteCommandAction(project, file) { @Override protected void run(Result result) throws Throwable { - final Extensions extensions = getExtension(plugin, extensionsList); + final Extensions extensions = getExtension(plugin, myEp.getName()); Extension extension = extensions.addExtension(myEp.getName()); XmlTag tag = extension.getXmlTag(); tag.setAttribute("implementationClass", myPsiClass.getQualifiedName()); @@ -152,11 +162,12 @@ class RegisterInspectionFix implements IntentionAction { PsiNavigateUtil.navigate(extension.getXmlTag()); } - private Extensions getExtension(IdeaPlugin plugin, List extensionsList) { + public static Extensions getExtension(IdeaPlugin plugin, String epName) { + final List extensionsList = plugin.getExtensions(); Extensions extensions = null; for (Extensions e : extensionsList) { String s = e.getDefaultExtensionNs().getStringValue(); - if (s != null && myEp.getName().startsWith(s)) { + if (s != null && epName.startsWith(s)) { extensions = e; break; } diff --git a/plugins/devkit/src/inspections/quickfix/RegisterInspectionFixProvider.java b/plugins/devkit/src/inspections/quickfix/RegisterInspectionFixProvider.java deleted file mode 100644 index c136d2726839..000000000000 --- a/plugins/devkit/src/inspections/quickfix/RegisterInspectionFixProvider.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 org.jetbrains.idea.devkit.inspections.quickfix; - -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInspection.GlobalInspectionTool; -import com.intellij.codeInspection.InspectionEP; -import com.intellij.codeInspection.LocalInspectionEP; -import com.intellij.codeInspection.LocalInspectionTool; -import com.intellij.codeInspection.reference.UnusedDeclarationFixProvider; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiIdentifier; -import com.intellij.psi.util.InheritanceUtil; -import org.jetbrains.annotations.NotNull; - -/** - * @author Dmitry Avdeev - * Date: 1/19/12 - */ -public class RegisterInspectionFixProvider implements UnusedDeclarationFixProvider { - - @NotNull - @Override - public IntentionAction[] getQuickFixes(PsiElement element) { - if (!(element instanceof PsiIdentifier)) return IntentionAction.EMPTY_ARRAY; - PsiElement parent = element.getParent(); - if (!(parent instanceof PsiClass)) return IntentionAction.EMPTY_ARRAY; - if (InheritanceUtil.isInheritor((PsiClass)parent, LocalInspectionTool.class.getName())) { - return new IntentionAction[] { new RegisterInspectionFix((PsiClass)parent, LocalInspectionEP.LOCAL_INSPECTION) }; - } - if (InheritanceUtil.isInheritor((PsiClass)parent, GlobalInspectionTool.class.getName())) { - return new IntentionAction[] { new RegisterInspectionFix((PsiClass)parent, InspectionEP.GLOBAL_INSPECTION) }; - } - return IntentionAction.EMPTY_ARRAY; - } -} diff --git a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/config/ReplacePolicy.java b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/config/ReplacePolicy.java index 2d01a464840f..e5714ed2a11e 100644 --- a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/config/ReplacePolicy.java +++ b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/config/ReplacePolicy.java @@ -36,7 +36,7 @@ public class ReplacePolicy implements ConflictResolutionPolicy { } public void setNewMethodStrategy(InsertNewMethodStrategy strategy) { - // not needed here + DuplicatePolicy.getInstance().setNewMethodStrategy(strategy); } public PsiMethod applyMethod(PsiClass clazz, PsiMethod existingMethod, @NotNull PsiMethod newMethod, Editor editor) throws IncorrectOperationException { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.java index c5788c3b889a..d2f8ba7f27ce 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.java @@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy; import com.intellij.CommonBundle; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.PropertyKey; import java.lang.ref.Reference; @@ -34,6 +35,7 @@ public class GroovyBundle { @NonNls private static final String BUNDLE = "org.jetbrains.plugins.groovy.GroovyBundle"; + @NotNull public static String message(@PropertyKey(resourceBundle = BUNDLE)String key, Object... params) { return CommonBundle.message(getBundle(), key, params); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java index ca405965f44d..81c831d3b2cf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java @@ -283,6 +283,8 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { return result; } + final GroovyFrameworkConfigNotification[] extensions = GroovyFrameworkConfigNotification.EP_NAME.getExtensions(); + final Semaphore semaphore = new Semaphore(); semaphore.down(); final AtomicReference>> ref = new AtomicReference>>(); @@ -299,7 +301,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { Set scriptFolders = new LinkedHashSet(); // perhaps a separate extension for that? - for (GroovyFrameworkConfigNotification extension : GroovyFrameworkConfigNotification.EP_NAME.getExtensions()) { + for (GroovyFrameworkConfigNotification extension : extensions) { File jarPath = new File(PathUtil.getJarPathForClass(extension.getClass())); if (jarPath.isFile()) { jarPath = jarPath.getParentFile(); @@ -330,13 +332,13 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { ourStandardScripts = new SoftReference>>(executors); ref.set(executors); } - catch (OutOfMemoryError e) { - stopGdsl = true; - throw e; - } - catch (NoClassDefFoundError e) { - stopGdsl = true; - throw e; + catch (Throwable e) { + ref.set(new ArrayList>()); + //noinspection InstanceofCatchParameter + if (e instanceof Error) { + stopGdsl = true; + } + LOG.error(e); } finally { semaphore.up(); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java index 46ad9f88d270..cea8a470b92c 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java @@ -27,6 +27,8 @@ import com.intellij.openapi.vcs.changes.ChangeListManagerImpl; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.AppUIUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.VcsBackgroundTask; import com.intellij.vcsUtil.VcsUtil; @@ -196,9 +198,15 @@ public class HgVFSListener extends VcsVFSListener { myDeletedFiles.clear(); // skip unversioned files and files which are not under Mercurial - final ChangeListManagerImpl changeListManager = ChangeListManagerImpl.getInstanceImpl(myProject); - skipUnversionedAndNotUnderHg(changeListManager, filesToDelete); - skipUnversionedAndNotUnderHg(changeListManager, filesToConfirmDeletion); + final List unversionedFiles = + ContainerUtil.map(ChangeListManagerImpl.getInstanceImpl(myProject).getUnversionedFiles(), new Function() { + @Override + public FilePath fun(VirtualFile virtualFile) { + return new FilePathImpl(virtualFile); + } + }); + skipUnversionedAndNotUnderHg(unversionedFiles, filesToDelete); + skipUnversionedAndNotUnderHg(unversionedFiles, filesToConfirmDeletion); // newly added files (which were added to the repo but never committed) should be removed from the VCS, // but without user confirmation. @@ -241,20 +249,21 @@ public class HgVFSListener extends VcsVFSListener { }.queue(); } - /** - * Changes the given collection of files by filtering out unversioned files and - * files which are not under Mercurial repository. - * @param changeListManager instance of the ChangeListManagerImpl to retrieve unversioned files from it. - * @param filesToFilter files to be filtered. - */ - private void skipUnversionedAndNotUnderHg(ChangeListManagerImpl changeListManager, Collection filesToFilter) { - for (Iterator iter = filesToFilter.iterator(); iter.hasNext(); ) { - final FilePath filePath = iter.next(); - if (HgUtil.getHgRootOrNull(myProject, filePath) == null || changeListManager.isUnversioned(filePath.getVirtualFile())) { - iter.remove(); + /** + * Changes the given collection of files by filtering out unversioned files and + * files which are not under Mercurial repository. + * + * @param unversionedFiles list of unversioned files + * @param filesToFilter files to be filtered. + */ + private void skipUnversionedAndNotUnderHg(List unversionedFiles, Collection filesToFilter) { + for (Iterator iter = filesToFilter.iterator(); iter.hasNext(); ) { + final FilePath filePath = iter.next(); + if (HgUtil.getHgRootOrNull(myProject, filePath) == null || unversionedFiles.contains(filePath)) { + iter.remove(); + } } } - } @Override protected void performDeletion( final List filesToDelete) { diff --git a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenArtifact.java b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenArtifact.java index f61b559400e2..560e19f2f271 100644 --- a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenArtifact.java +++ b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenArtifact.java @@ -16,6 +16,7 @@ package org.jetbrains.idea.maven.model; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; @@ -23,7 +24,6 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.Serializable; -import java.text.MessageFormat; public class MavenArtifact implements Serializable { @@ -177,25 +177,39 @@ public class MavenArtifact implements Serializable { public String getPathForExtraArtifact(@Nullable String extraArtifactClassifier, @Nullable String customExtension) { String path = getPath(); - if (!StringUtil.isEmptyOrSpaces(extraArtifactClassifier)) { - int repoEnd = path.lastIndexOf(getRelativePath()); - - if (repoEnd == -1) { - // unknown path format: try to add a classified at the end of the filename - int dotPos = path.lastIndexOf("."); - if (dotPos != -1) {// sometimes path doesn't contain '.'; but i can't find any reason why. - String withoutExtension = path.substring(0, dotPos); - path = MessageFormat.format("{0}-{1}.{2}", - withoutExtension, - extraArtifactClassifier, - customExtension == null ? myExtension : customExtension); - } - } - else { - String repoPath = path.substring(0, repoEnd); - path = repoPath + getRelativePathForExtraArtifact(extraArtifactClassifier, customExtension); - } + if (extraArtifactClassifier == null && customExtension == null && Comparing.equal(myVersion, myBaseVersion)) { + return path; } + + int slashPos = path.lastIndexOf('/'); + if (slashPos != -1) { + StringBuilder res = new StringBuilder(); + res.append(path, 0, slashPos + 1); + res.append(myArtifactId); + res.append('-'); + res.append(myVersion); + + String fullClassifier = getFullClassifier(extraArtifactClassifier); + if (fullClassifier != null) { + res.append('-').append(fullClassifier); + } + + res.append('.'); + res.append(customExtension == null ? myExtension : customExtension); + return res.toString(); + } + + // unknown path format: try to add a classified at the end of the filename + int dotPos = path.lastIndexOf('.'); + if (dotPos != -1) {// sometimes path doesn't contain '.'; but i can't find any reason why. + StringBuilder res = new StringBuilder(); + res.append(path, 0, dotPos); + res.append('-'); + res.append(extraArtifactClassifier); + res.append(customExtension == null ? myExtension : customExtension); + return res.toString(); + } + return path; } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenDefaultModifiableModelsProvider.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenDefaultModifiableModelsProvider.java index 81ddd7cbdc2b..2599d5861775 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenDefaultModifiableModelsProvider.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenDefaultModifiableModelsProvider.java @@ -106,47 +106,39 @@ public class MavenDefaultModifiableModelsProvider extends MavenBaseModifiableMod } public void commit() { - MavenUtil.invokeAndWaitWriteAction(myProject, new Runnable() { + ((ProjectRootManagerEx)ProjectRootManager.getInstance(myProject)).mergeRootsChangesDuring(new Runnable() { public void run() { - ((ProjectRootManagerEx)ProjectRootManager.getInstance(myProject)).mergeRootsChangesDuring(new Runnable() { - public void run() { - processExternalArtifactDependencies(); - for (Library.ModifiableModel each : myLibraryModels.values()) { - each.commit(); - } - myLibrariesModel.commit(); - Collection rootModels = myRootModels.values(); + processExternalArtifactDependencies(); + for (Library.ModifiableModel each : myLibraryModels.values()) { + each.commit(); + } + myLibrariesModel.commit(); + Collection rootModels = myRootModels.values(); - ModifiableRootModel[] rootModels1 = rootModels.toArray(new ModifiableRootModel[rootModels.size()]); - for (ModifiableRootModel model : rootModels1) { - assert !model.isDisposed() : "Already disposed: " + model; - } - ModifiableModelCommitter.multiCommit(rootModels1, myModuleModel); + ModifiableRootModel[] rootModels1 = rootModels.toArray(new ModifiableRootModel[rootModels.size()]); + for (ModifiableRootModel model : rootModels1) { + assert !model.isDisposed() : "Already disposed: " + model; + } + ModifiableModelCommitter.multiCommit(rootModels1, myModuleModel); - for (ModifiableFacetModel each : myFacetModels.values()) { - each.commit(); - } - if (myArtifactModel != null) { - myArtifactModel.commit(); - } - } - }); + for (ModifiableFacetModel each : myFacetModels.values()) { + each.commit(); + } + if (myArtifactModel != null) { + myArtifactModel.commit(); + } } }); } public void dispose() { - MavenUtil.invokeAndWaitWriteAction(myProject, new Runnable() { - public void run() { - for (ModifiableRootModel each : myRootModels.values()) { - each.dispose(); - } - myModuleModel.dispose(); - if (myArtifactModel != null) { - myArtifactModel.dispose(); - } - } - }); + for (ModifiableRootModel each : myRootModels.values()) { + each.dispose(); + } + myModuleModel.dispose(); + if (myArtifactModel != null) { + myArtifactModel.dispose(); + } } public ModalityState getModalityStateForQuestionDialogs() { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java index f7e2e59ea715..ee7fc3d3d821 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java @@ -48,13 +48,7 @@ import java.util.Map; public class MavenModuleImporter { - public static final String PROFILE_PREFIX = "Annotation profile for "; - - public static final String MAVEN_DEFAULT_ANNOTATION_PROFILE = "Maven default annotation processors profile"; - public static final String SUREFIRE_PLUGIN_LIBRARY_NAME = "maven-surefire-plugin urls"; - public static final String DEFAULT_ANNOTATION_PATH_OUTPUT = "target/generated-sources/annotations"; - public static final String DEFAULT_TEST_ANNOTATION_OUTPUT = "target/generated-test-sources/test-annotations"; private final Module myModule; private final MavenProjectsTree myMavenTree; @@ -94,26 +88,6 @@ public class MavenModuleImporter { configFolders(); configDependencies(); configLanguageLevel(); - configAnnotationProcessors(); - excludeFromCompilationArchetypeResources(); - } - - private void excludeFromCompilationArchetypeResources() { - VirtualFile directoryFile = myMavenProject.getDirectoryFile(); - - VirtualFile archetypeResourcesDir = VfsUtil.findRelativeFile(directoryFile, "src", "main", "resources", "archetype-resources"); - - if (archetypeResourcesDir != null) { - Project project = myModule.getProject(); - - CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(project); - - if (!compilerConfiguration.isExcludedFromCompilation(archetypeResourcesDir)) { - ExcludedEntriesConfiguration cfg = compilerConfiguration.getExcludedEntriesConfiguration(); - - cfg.addExcludeEntryDescription(new ExcludeEntryDescription(archetypeResourcesDir, true, false, project)); - } - } } public void preConfigFacets() { @@ -267,139 +241,6 @@ public class MavenModuleImporter { } } - private void configAnnotationProcessors() { - if (Boolean.parseBoolean(System.getProperty("idea.maven.keep.annotation.processors"))) return; - - Sdk sdk = ModuleRootManager.getInstance(myModule).getSdk(); - if (sdk != null) { - String versionString = sdk.getVersionString(); - if (versionString != null) { - if (versionString.contains("1.5") || versionString.contains("1.4") || versionString.contains("1.3") || versionString.contains("1.2")) { - return; - } - } - } - - CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance( - myModule.getProject()); - - ProcessorConfigProfile currentProfile = compilerConfiguration.getAnnotationProcessingConfiguration(myModule); - - String moduleProfileName = PROFILE_PREFIX + myModule.getName(); - - if (currentProfile != compilerConfiguration.getDefaultProcessorProfile() - && !MAVEN_DEFAULT_ANNOTATION_PROFILE.equals(currentProfile.getName()) - && !moduleProfileName.equals(currentProfile.getName())) { - return; - } - - ProcessorConfigProfile moduleProfile = compilerConfiguration.findModuleProcessorProfile(moduleProfileName); - - ProcessorConfigProfile defaultMavenProfile = compilerConfiguration.findModuleProcessorProfile(MAVEN_DEFAULT_ANNOTATION_PROFILE); - - if (shouldEnableAnnotationProcessors()) { - String annotationProcessorDirectory = getRelativeAnnotationProcessorDirectory(false); - if (annotationProcessorDirectory == null) { - annotationProcessorDirectory = DEFAULT_ANNOTATION_PATH_OUTPUT; - } - - String testAnnotationProcessorDirectory = getRelativeAnnotationProcessorDirectory(true); - if (testAnnotationProcessorDirectory == null) { - testAnnotationProcessorDirectory = DEFAULT_TEST_ANNOTATION_OUTPUT; - } - - Map options = myMavenProject.getAnnotationProcessorOptions(); - - List processors = myMavenProject.getDeclaredAnnotationProcessors(); - - if (processors == null - && options.isEmpty() - && DEFAULT_ANNOTATION_PATH_OUTPUT.equals(annotationProcessorDirectory.replace('\\', '/')) - && DEFAULT_TEST_ANNOTATION_OUTPUT.equals(testAnnotationProcessorDirectory.replace('\\', '/'))) { - if (moduleProfile != null) { - compilerConfiguration.removeModuleProcessorProfile(moduleProfile); - } - - if (defaultMavenProfile == null) { - defaultMavenProfile = new ProcessorConfigProfileImpl(MAVEN_DEFAULT_ANNOTATION_PROFILE); - defaultMavenProfile.setEnabled(true); - defaultMavenProfile.setOutputRelativeToContentRoot(true); - defaultMavenProfile.setObtainProcessorsFromClasspath(true); - defaultMavenProfile.setGeneratedSourcesDirectoryName(DEFAULT_ANNOTATION_PATH_OUTPUT, false); - defaultMavenProfile.setGeneratedSourcesDirectoryName(DEFAULT_TEST_ANNOTATION_OUTPUT, true); - compilerConfiguration.addModuleProcessorProfile(defaultMavenProfile); - } - - defaultMavenProfile.addModuleName(myModule.getName()); - } - else { - if (defaultMavenProfile != null) { - defaultMavenProfile.removeModuleName(myModule.getName()); - - if (defaultMavenProfile.getModuleNames().isEmpty()) { - compilerConfiguration.removeModuleProcessorProfile(defaultMavenProfile); - } - } - - if (moduleProfile == null) { - moduleProfile = new ProcessorConfigProfileImpl(moduleProfileName); - moduleProfile.setOutputRelativeToContentRoot(true); - moduleProfile.setEnabled(true); - moduleProfile.setObtainProcessorsFromClasspath(true); - moduleProfile.addModuleName(myModule.getName()); - compilerConfiguration.addModuleProcessorProfile(moduleProfile); - } - - moduleProfile.setGeneratedSourcesDirectoryName(annotationProcessorDirectory, false); - moduleProfile.setGeneratedSourcesDirectoryName(testAnnotationProcessorDirectory, true); - - moduleProfile.clearProcessorOptions(); - for (Map.Entry entry : options.entrySet()) { - moduleProfile.setOption(entry.getKey(), entry.getValue()); - } - - moduleProfile.clearProcessors(); - - if (processors != null) { - for (String processor : processors) { - moduleProfile.addProcessor(processor); - } - } - } - } - else { - if (defaultMavenProfile != null) { - defaultMavenProfile.removeModuleName(myModule.getName()); - - if (defaultMavenProfile.getModuleNames().isEmpty()) { - compilerConfiguration.removeModuleProcessorProfile(defaultMavenProfile); - } - } - - if (moduleProfile != null) { - compilerConfiguration.removeModuleProcessorProfile(moduleProfile); - } - } - } - - @Nullable - private String getRelativeAnnotationProcessorDirectory(boolean isTest) { - String annotationProcessorDirectory = myMavenProject.getAnnotationProcessorDirectory(isTest); - File annotationProcessorDirectoryFile = new File(annotationProcessorDirectory); - if (!annotationProcessorDirectoryFile.isAbsolute()) { - return annotationProcessorDirectory; - } - - String absoluteProjectDirectory = myMavenProject.getDirectory(); - return FileUtil.getRelativePath(new File(absoluteProjectDirectory), annotationProcessorDirectoryFile); - } - - private boolean shouldEnableAnnotationProcessors() { - if ("pom".equals(myMavenProject.getPackaging())) return false; - - return myMavenProject.getProcMode() != MavenProject.ProcMode.NONE || myMavenProject.getPluginConfiguration("org.bsc.maven", "maven-processor-plugin") != null; - } - @NotNull private static DependencyScope selectScope(String mavenScope) { if (MavenConstants.SCOPE_RUNTIME.equals(mavenScope)) return DependencyScope.RUNTIME; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java index 33889304badf..b05efa89378e 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenProjectImporter.java @@ -15,8 +15,6 @@ */ package org.jetbrains.idea.maven.importing; -import com.intellij.compiler.CompilerConfiguration; -import com.intellij.compiler.CompilerConfigurationImpl; import com.intellij.compiler.impl.javaCompiler.javac.JavacConfiguration; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.ModifiableModuleModel; @@ -33,13 +31,13 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.encoding.EncodingProjectManager; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.containers.Stack; import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.maven.importing.configurers.MavenModuleConfigurer; import org.jetbrains.idea.maven.model.MavenArtifact; import org.jetbrains.idea.maven.project.*; import org.jetbrains.idea.maven.utils.MavenLog; @@ -50,9 +48,6 @@ import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerOptions; import java.io.File; import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.UnsupportedCharsetException; import java.util.*; public class MavenProjectImporter { @@ -95,20 +90,20 @@ public class MavenProjectImporter { public List importProject() { List postTasks = new ArrayList(); - boolean hasChanges = false; + boolean hasChanges; // in the case projects are changed during importing we must memorise them myAllProjects = new LinkedHashSet(myProjectsTree.getProjects()); myAllProjects.addAll(myProjectsToImportWithChanges.keySet()); // some projects may already have been removed from the tree - hasChanges |= deleteIncompatibleModules(); + hasChanges = deleteIncompatibleModules(); myProjectsToImportWithChanges = collectProjectsToImport(myProjectsToImportWithChanges); mapMavenProjectsToModulesAndNames(); if (myProject.isDisposed()) return null; - boolean projectsHaveChanges = projectsToImportHaveChanges(); + final boolean projectsHaveChanges = projectsToImportHaveChanges(); if (projectsHaveChanges) { hasChanges = true; importModules(postTasks); @@ -128,16 +123,30 @@ public class MavenProjectImporter { removeUnusedProjectLibraries(); } - if (hasChanges) { - myModelsProvider.commit(); + final boolean finalHasChanges = hasChanges; - if (projectsHaveChanges) { - configSettings(); + MavenUtil.invokeAndWaitWriteAction(myProject, new Runnable() { + public void run() { + if (finalHasChanges) { + myModelsProvider.commit(); + + if (projectsHaveChanges) { + removeOutdatedCompilerConfigSettings(); + + for (MavenProject mavenProject : myAllProjects) { + Module module = myMavenProjectToModule.get(mavenProject); + + for (MavenModuleConfigurer configurer : MavenModuleConfigurer.getConfigurers()) { + configurer.configure(mavenProject, myProject, module); + } + } + } + } + else { + myModelsProvider.dispose(); + } } - } - else { - myModelsProvider.dispose(); - } + }); return postTasks; } @@ -327,6 +336,10 @@ public class MavenProjectImporter { }, "\n"); } + private static void doRefreshFiles(Set files) { + LocalFileSystem.getInstance().refreshIoFiles(files); + } + private void scheduleRefreshResolvedArtifacts(List postTasks) { // We have to refresh all the resolved artifacts manually in order to // update all the VirtualFilePointers. It is not enough to call @@ -346,21 +359,15 @@ public class MavenProjectImporter { if (each.isResolved()) files.add(each.getFile()); } - final Runnable r = new Runnable() { - public void run() { - LocalFileSystem.getInstance().refreshIoFiles(files); - } - }; - if (ApplicationManager.getApplication().isUnitTestMode()) { - r.run(); + doRefreshFiles(files); } else { postTasks.add(new MavenProjectsProcessorTask() { public void perform(Project project, MavenEmbeddersManager embeddersManager, MavenConsole console, MavenProgressIndicator indicator) throws MavenProcessCanceledException { indicator.setText("Refreshing files..."); - r.run(); + doRefreshFiles(files); } }); } @@ -381,41 +388,13 @@ public class MavenProjectImporter { myImportingSettings.getDedicatedModuleDir()); } - private void configSettings() { - MavenUtil.invokeAndWaitWriteAction(myProject, new Runnable() { - public void run() { - CompilerConfigurationImpl configuration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject); + private void removeOutdatedCompilerConfigSettings() { + ApplicationManager.getApplication().assertWriteAccessAllowed(); - MavenProjectsManager projectsManager = MavenProjectsManager.getInstance(myProject); - - for (MavenProject project : myAllProjects) { - String targetLevel = project.getTargetLevel(); - - if (targetLevel != null) { - Module module = projectsManager.findModule(project); - if (module != null) { - configuration.setBytecodeTargetLevel(module, targetLevel); - } - } - - if (!Boolean.parseBoolean(System.getProperty("maven.disable.encode.import"))) { - String encoding = project.getEncoding(); - if (encoding != null) { - try { - EncodingProjectManager.getInstance(myProject).setEncoding(project.getDirectoryFile(), Charset.forName(encoding)); - } - catch (UnsupportedCharsetException ignored) {/**/} - catch (IllegalCharsetNameException ignored) {/**/} - } - } - } - - final JpsJavaCompilerOptions javacOptions = JavacConfiguration.getOptions(myProject, JavacConfiguration.class); - String options = javacOptions.ADDITIONAL_OPTIONS_STRING; - options = options.replaceFirst("(-target (\\S+))", ""); // Old IDEAs saved - javacOptions.ADDITIONAL_OPTIONS_STRING = options; - } - }); + final JpsJavaCompilerOptions javacOptions = JavacConfiguration.getOptions(myProject, JavacConfiguration.class); + String options = javacOptions.ADDITIONAL_OPTIONS_STRING; + options = options.replaceFirst("(-target (\\S+))", ""); // Old IDEAs saved + javacOptions.ADDITIONAL_OPTIONS_STRING = options; } private void importModules(final List postTasks) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenUIModifiableModelsProvider.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenUIModifiableModelsProvider.java index f0ec25c6f429..a35f2f6fecfa 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenUIModifiableModelsProvider.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenUIModifiableModelsProvider.java @@ -95,11 +95,7 @@ public class MavenUIModifiableModelsProvider extends MavenBaseModifiableModelsPr } public void commit() { - MavenUtil.invokeAndWaitWriteAction(myProject, new Runnable() { - public void run() { - processExternalArtifactDependencies(); - } - }); + processExternalArtifactDependencies(); } public void dispose() { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenAnnotationProcessorConfigurer.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenAnnotationProcessorConfigurer.java new file mode 100644 index 000000000000..f1604575ff51 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenAnnotationProcessorConfigurer.java @@ -0,0 +1,179 @@ +/* + * Copyright 2000-2013 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.idea.maven.importing.configurers; + +import com.intellij.compiler.CompilerConfiguration; +import com.intellij.compiler.CompilerConfigurationImpl; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.maven.project.MavenProject; +import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile; +import org.jetbrains.jps.model.java.impl.compiler.ProcessorConfigProfileImpl; + +import java.io.File; +import java.util.List; +import java.util.Map; + +/** + * @author Sergey Evdokimov + */ +public class MavenAnnotationProcessorConfigurer extends MavenModuleConfigurer { + + public static final String PROFILE_PREFIX = "Annotation profile for "; + public static final String MAVEN_DEFAULT_ANNOTATION_PROFILE = "Maven default annotation processors profile"; + public static final String DEFAULT_ANNOTATION_PATH_OUTPUT = "target/generated-sources/annotations"; + public static final String DEFAULT_TEST_ANNOTATION_OUTPUT = "target/generated-test-sources/test-annotations"; + + @Override + public void configure(@NotNull MavenProject mavenProject, @NotNull Project project, @Nullable Module module) { + if (module == null) return; + + Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); + if (sdk != null) { + String versionString = sdk.getVersionString(); + if (versionString != null) { + if (versionString.contains("1.5") || versionString.contains("1.4") || versionString.contains("1.3") || versionString.contains("1.2")) { + return; + } + } + } + + CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(project); + + ProcessorConfigProfile currentProfile = compilerConfiguration.getAnnotationProcessingConfiguration(module); + + String moduleProfileName = PROFILE_PREFIX + module.getName(); + + if (currentProfile != compilerConfiguration.getDefaultProcessorProfile() + && !MAVEN_DEFAULT_ANNOTATION_PROFILE.equals(currentProfile.getName()) + && !moduleProfileName.equals(currentProfile.getName())) { + return; + } + + ProcessorConfigProfile moduleProfile = compilerConfiguration.findModuleProcessorProfile(moduleProfileName); + + ProcessorConfigProfile defaultMavenProfile = compilerConfiguration.findModuleProcessorProfile(MAVEN_DEFAULT_ANNOTATION_PROFILE); + + if (shouldEnableAnnotationProcessors(mavenProject)) { + String annotationProcessorDirectory = getRelativeAnnotationProcessorDirectory(mavenProject, false); + if (annotationProcessorDirectory == null) { + annotationProcessorDirectory = DEFAULT_ANNOTATION_PATH_OUTPUT; + } + + String testAnnotationProcessorDirectory = getRelativeAnnotationProcessorDirectory(mavenProject, true); + if (testAnnotationProcessorDirectory == null) { + testAnnotationProcessorDirectory = DEFAULT_TEST_ANNOTATION_OUTPUT; + } + + Map options = mavenProject.getAnnotationProcessorOptions(); + + List processors = mavenProject.getDeclaredAnnotationProcessors(); + + if (processors == null + && options.isEmpty() + && DEFAULT_ANNOTATION_PATH_OUTPUT.equals(annotationProcessorDirectory.replace('\\', '/')) + && DEFAULT_TEST_ANNOTATION_OUTPUT.equals(testAnnotationProcessorDirectory.replace('\\', '/'))) { + if (moduleProfile != null) { + compilerConfiguration.removeModuleProcessorProfile(moduleProfile); + } + + if (defaultMavenProfile == null) { + defaultMavenProfile = new ProcessorConfigProfileImpl(MAVEN_DEFAULT_ANNOTATION_PROFILE); + defaultMavenProfile.setEnabled(true); + defaultMavenProfile.setOutputRelativeToContentRoot(true); + defaultMavenProfile.setObtainProcessorsFromClasspath(true); + defaultMavenProfile.setGeneratedSourcesDirectoryName(DEFAULT_ANNOTATION_PATH_OUTPUT, false); + defaultMavenProfile.setGeneratedSourcesDirectoryName(DEFAULT_TEST_ANNOTATION_OUTPUT, true); + compilerConfiguration.addModuleProcessorProfile(defaultMavenProfile); + } + + defaultMavenProfile.addModuleName(module.getName()); + } + else { + if (defaultMavenProfile != null) { + defaultMavenProfile.removeModuleName(module.getName()); + + if (defaultMavenProfile.getModuleNames().isEmpty()) { + compilerConfiguration.removeModuleProcessorProfile(defaultMavenProfile); + } + } + + if (moduleProfile == null) { + moduleProfile = new ProcessorConfigProfileImpl(moduleProfileName); + moduleProfile.setOutputRelativeToContentRoot(true); + moduleProfile.setEnabled(true); + moduleProfile.setObtainProcessorsFromClasspath(true); + moduleProfile.addModuleName(module.getName()); + compilerConfiguration.addModuleProcessorProfile(moduleProfile); + } + + moduleProfile.setGeneratedSourcesDirectoryName(annotationProcessorDirectory, false); + moduleProfile.setGeneratedSourcesDirectoryName(testAnnotationProcessorDirectory, true); + + moduleProfile.clearProcessorOptions(); + for (Map.Entry entry : options.entrySet()) { + moduleProfile.setOption(entry.getKey(), entry.getValue()); + } + + moduleProfile.clearProcessors(); + + if (processors != null) { + for (String processor : processors) { + moduleProfile.addProcessor(processor); + } + } + } + } + else { + if (defaultMavenProfile != null) { + defaultMavenProfile.removeModuleName(module.getName()); + + if (defaultMavenProfile.getModuleNames().isEmpty()) { + compilerConfiguration.removeModuleProcessorProfile(defaultMavenProfile); + } + } + + if (moduleProfile != null) { + compilerConfiguration.removeModuleProcessorProfile(moduleProfile); + } + } + } + + @Nullable + private String getRelativeAnnotationProcessorDirectory(MavenProject mavenProject, boolean isTest) { + String annotationProcessorDirectory = mavenProject.getAnnotationProcessorDirectory(isTest); + File annotationProcessorDirectoryFile = new File(annotationProcessorDirectory); + if (!annotationProcessorDirectoryFile.isAbsolute()) { + return annotationProcessorDirectory; + } + + String absoluteProjectDirectory = mavenProject.getDirectory(); + return FileUtil.getRelativePath(new File(absoluteProjectDirectory), annotationProcessorDirectoryFile); + } + + private static boolean shouldEnableAnnotationProcessors(MavenProject mavenProject) { + if ("pom".equals(mavenProject.getPackaging())) return false; + + return mavenProject.getProcMode() != MavenProject.ProcMode.NONE + || mavenProject.getPluginConfiguration("org.bsc.maven", "maven-processor-plugin") != null; + } + +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenCompilerConfigurer.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenCompilerConfigurer.java new file mode 100644 index 000000000000..afd4bc786fef --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenCompilerConfigurer.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2013 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.idea.maven.importing.configurers; + +import com.intellij.compiler.CompilerConfiguration; +import com.intellij.compiler.CompilerConfigurationImpl; +import com.intellij.openapi.compiler.options.ExcludeEntryDescription; +import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.maven.project.MavenProject; + +/** + * @author Sergey Evdokimov + */ +public class MavenCompilerConfigurer extends MavenModuleConfigurer { + @Override + public void configure(@NotNull MavenProject mavenProject, @NotNull Project project, @Nullable Module module) { + if (module == null) return; + + String targetLevel = mavenProject.getTargetLevel(); + if (targetLevel != null) { + CompilerConfigurationImpl configuration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(project); + configuration.setBytecodeTargetLevel(module, targetLevel); + } + + VirtualFile directoryFile = mavenProject.getDirectoryFile(); + + // Exclude src/main/archetype-resources + VirtualFile archetypeResourcesDir = VfsUtil.findRelativeFile(directoryFile, "src", "main", "resources", "archetype-resources"); + + if (archetypeResourcesDir != null) { + CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(project); + + if (!compilerConfiguration.isExcludedFromCompilation(archetypeResourcesDir)) { + ExcludedEntriesConfiguration cfg = compilerConfiguration.getExcludedEntriesConfiguration(); + + cfg.addExcludeEntryDescription(new ExcludeEntryDescription(archetypeResourcesDir, true, false, project)); + } + } + } +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenEncodingConfigurer.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenEncodingConfigurer.java new file mode 100644 index 000000000000..cb05f6b3b028 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenEncodingConfigurer.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2013 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.idea.maven.importing.configurers; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.encoding.EncodingProjectManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.maven.project.MavenProject; + +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; + +/** + * @author Sergey Evdokimov + */ +public class MavenEncodingConfigurer extends MavenModuleConfigurer { + @Override + public void configure(@NotNull MavenProject mavenProject, @NotNull Project project, @Nullable Module module) { + String encoding = mavenProject.getEncoding(); + if (encoding != null) { + try { + EncodingProjectManager.getInstance(project).setEncoding(mavenProject.getDirectoryFile(), Charset.forName(encoding)); + } + catch (UnsupportedCharsetException ignored) {/**/} + catch (IllegalCharsetNameException ignored) {/**/} + } + } +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenModuleConfigurer.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenModuleConfigurer.java new file mode 100644 index 000000000000..eb60d8253c2c --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenModuleConfigurer.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2013 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.idea.maven.importing.configurers; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.maven.project.MavenProject; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Sergey Evdokimov + */ +public abstract class MavenModuleConfigurer { + + private static volatile List ourConfigurersList; + + public abstract void configure(@NotNull MavenProject mavenProject, @NotNull Project project, @Nullable Module module); + + public static List getConfigurers() { + List configurers = ourConfigurersList; + if (configurers == null) { + configurers = new ArrayList(); + + for (MavenModuleConfigurer configurer : new MavenModuleConfigurer[]{ + new MavenCompilerConfigurer(), + new MavenEncodingConfigurer(), + new MavenAnnotationProcessorConfigurer()}) { + + if (!Boolean.parseBoolean(System.getProperty("idea.maven.disable." + configurer.getClass().getSimpleName()))) { + configurers.add(configurer); + } + } + + ourConfigurersList = configurers; + } + + return configurers; + } + +} diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/AnnotationProcessorImportingTest.groovy b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/AnnotationProcessorImportingTest.groovy index e5c4ec6a8386..097b891adcbc 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/AnnotationProcessorImportingTest.groovy +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/AnnotationProcessorImportingTest.groovy @@ -18,7 +18,8 @@ package org.jetbrains.idea.maven.compiler import com.intellij.compiler.CompilerConfiguration import com.intellij.compiler.CompilerConfigurationImpl import org.jetbrains.idea.maven.MavenImportingTestCase -import org.jetbrains.idea.maven.importing.MavenModuleImporter +import org.jetbrains.idea.maven.importing.configurers.MavenAnnotationProcessorConfigurer + /** * @author Sergey Evdokimov */ @@ -125,10 +126,10 @@ class AnnotationProcessorImportingTest extends MavenImportingTestCase { def compilerConfiguration = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)) - assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.MAVEN_DEFAULT_ANNOTATION_PROFILE).getModuleNames() == new HashSet(["module1"]) - assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.PROFILE_PREFIX + 'module2').getProcessors() == new HashSet(["com.test.SourceCodeGeneratingAnnotationProcessor2"]) - assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.PROFILE_PREFIX + 'module3') == null - assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.PROFILE_PREFIX + 'module3_1') == null + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.MAVEN_DEFAULT_ANNOTATION_PROFILE).getModuleNames() == new HashSet(["module1"]) + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.PROFILE_PREFIX + 'module2').getProcessors() == new HashSet(["com.test.SourceCodeGeneratingAnnotationProcessor2"]) + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.PROFILE_PREFIX + 'module3') == null + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.PROFILE_PREFIX + 'module3_1') == null } public void testOverrideGeneratedOutputDir() { @@ -152,8 +153,8 @@ class AnnotationProcessorImportingTest extends MavenImportingTestCase { def compilerConfiguration = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)) - assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.MAVEN_DEFAULT_ANNOTATION_PROFILE) == null - assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.PROFILE_PREFIX + "project").getGeneratedSourcesDirectoryName(false).replace('\\', '/').endsWith("out/generated") + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.MAVEN_DEFAULT_ANNOTATION_PROFILE) == null + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.PROFILE_PREFIX + "project").getGeneratedSourcesDirectoryName(false).replace('\\', '/').endsWith("out/generated") } public void testImportAnnotationProcessorOptions() { @@ -180,8 +181,8 @@ class AnnotationProcessorImportingTest extends MavenImportingTestCase { def compilerConfiguration = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)) - assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.MAVEN_DEFAULT_ANNOTATION_PROFILE) == null - def processorOptions = compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.PROFILE_PREFIX + "project").getProcessorOptions() + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.MAVEN_DEFAULT_ANNOTATION_PROFILE) == null + def processorOptions = compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.PROFILE_PREFIX + "project").getProcessorOptions() assert new HashMap(processorOptions) == ['opt1': '111', 'opt2': '222', 'opt3': '333'] } @@ -226,8 +227,8 @@ class AnnotationProcessorImportingTest extends MavenImportingTestCase { def compilerConfiguration = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)) - assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.MAVEN_DEFAULT_ANNOTATION_PROFILE) == null - def profile = compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.PROFILE_PREFIX + "project") + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.MAVEN_DEFAULT_ANNOTATION_PROFILE) == null + def profile = compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.PROFILE_PREFIX + "project") assert profile.getGeneratedSourcesDirectoryName(false).replace('\\', '/').endsWith("target/metamodel") assert profile.getGeneratedSourcesDirectoryName(true).replace('\\', '/').endsWith("target/metamodelTest") } @@ -284,8 +285,8 @@ class AnnotationProcessorImportingTest extends MavenImportingTestCase { def compilerConfiguration = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)) - assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.MAVEN_DEFAULT_ANNOTATION_PROFILE) == null - def profile = compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.PROFILE_PREFIX + "project") + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.MAVEN_DEFAULT_ANNOTATION_PROFILE) == null + def profile = compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.PROFILE_PREFIX + "project") assert profile.getGeneratedSourcesDirectoryName(false).replace('\\', '/').endsWith("target/metamodel") assert profile.getGeneratedSourcesDirectoryName(true).replace('\\', '/').endsWith("target/metamodelTest") } diff --git a/plugins/properties/src/com/intellij/lang/properties/references/PropertyReferenceBase.java b/plugins/properties/src/com/intellij/lang/properties/references/PropertyReferenceBase.java index 993be84b5d08..3c4c0d8bb655 100644 --- a/plugins/properties/src/com/intellij/lang/properties/references/PropertyReferenceBase.java +++ b/plugins/properties/src/com/intellij/lang/properties/references/PropertyReferenceBase.java @@ -191,6 +191,7 @@ public abstract class PropertyReferenceBase implements PsiPolyVariantReference, return mySoft; } + @NotNull public String getUnresolvedMessagePattern() { return PropertiesBundle.message("unresolved.property.key"); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltReferenceContributor.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltReferenceContributor.java index 85057da43b88..e2d3277351a7 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltReferenceContributor.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltReferenceContributor.java @@ -134,6 +134,7 @@ public class XsltReferenceContributor { return name.equals(text) || text.endsWith(":" + name); } + @NotNull @Override public String getUnresolvedMessagePattern() { return "Unknown Type"; diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/ModeReference.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/ModeReference.java index 3867949f0b27..529fcc323124 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/ModeReference.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/ModeReference.java @@ -187,6 +187,7 @@ class ModeReference extends SimpleAttributeReference implements PsiPolyVariantRe } } + @NotNull public String getUnresolvedMessagePattern() { final QName qName = myImplicitModeElement.getQName(); if (qName != null && qName != QNameUtil.UNRESOLVED) { diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/PrefixReference.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/PrefixReference.java index 837350475d81..0cfb85649ac0 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/PrefixReference.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/PrefixReference.java @@ -70,6 +70,7 @@ public class PrefixReference extends SimpleAttributeReference implements EmptyRe return XsltNamespaceContext.resolvePrefix(getCanonicalText(), myAttribute); } + @NotNull public String getUnresolvedMessagePattern() { return "Undeclared namespace prefix ''{0}''"; } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/TemplateReference.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/TemplateReference.java index 8048ce911bec..6dc05ff99bdb 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/TemplateReference.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/TemplateReference.java @@ -86,6 +86,7 @@ class TemplateReference extends AttributeReference implements EmptyResolveMessag QuickFixAction.registerQuickFixAction(highlightInfo, new CreateTemplateFix(myAttribute.getParent(), myName)); } + @NotNull public String getUnresolvedMessagePattern() { return "Cannot resolve template ''{0}''"; } diff --git a/resources/src/idea/RichPlatformPlugin.xml b/resources/src/idea/RichPlatformPlugin.xml index 6c954350cad5..d8d26ecf56e1 100644 --- a/resources/src/idea/RichPlatformPlugin.xml +++ b/resources/src/idea/RichPlatformPlugin.xml @@ -27,9 +27,9 @@ - - - + + + @@ -97,9 +97,9 @@ - - - + + + @@ -383,7 +383,7 @@ - + diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GenericDomValueReference.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GenericDomValueReference.java index 06a47b9f7644..881630e16325 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/GenericDomValueReference.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GenericDomValueReference.java @@ -142,6 +142,7 @@ public class GenericDomValueReference extends PsiReferenceBase im return StringUtil.notNullize(getStringValue()); } + @NotNull public String getUnresolvedMessagePattern() { final ConvertContext context = getConvertContext(); return getConverter().getErrorMessage(getStringValue(), context); diff --git a/xml/dom-openapi/src/com/intellij/util/xml/converters/DelimitedListConverter.java b/xml/dom-openapi/src/com/intellij/util/xml/converters/DelimitedListConverter.java index 2e5c825dd3ee..0b6a1d5e75a9 100644 --- a/xml/dom-openapi/src/com/intellij/util/xml/converters/DelimitedListConverter.java +++ b/xml/dom-openapi/src/com/intellij/util/xml/converters/DelimitedListConverter.java @@ -251,6 +251,7 @@ public abstract class DelimitedListConverter extends ResolvingConverter extends ResolvingConverter impl return getReferenceVariants(myContext, myGenericDomValue, getRangeInElement()); } + @NotNull public String getUnresolvedMessagePattern() { return myBadQuotation? DomBundle.message("message.invalid.value.quotation") : getUnresolvedMessage(getValue()); } diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/XmlErrorMessages.java b/xml/impl/src/com/intellij/codeInsight/daemon/XmlErrorMessages.java index dab60a7a6a0c..77d0c1ee4b3b 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/XmlErrorMessages.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/XmlErrorMessages.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.daemon; import com.intellij.CommonBundle; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.PropertyKey; import java.lang.ref.Reference; @@ -34,6 +35,7 @@ public class XmlErrorMessages { private XmlErrorMessages() { } + @NotNull public static String message(@PropertyKey(resourceBundle = BUNDLE)String key, Object... params) { return CommonBundle.message(getBundle(), key, params); } diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java index 59d987996ffa..d63164ac72a2 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java @@ -65,6 +65,7 @@ public class XmlEncodingReference implements PsiReference, EmptyResolveMessagePr //return myValue.getManager().findClass(fqn, GlobalSearchScope.allScope(myValue.getProject())); } + @NotNull public String getUnresolvedMessagePattern() { //noinspection UnresolvedPropertyKey return XmlErrorMessages.message("unknown.encoding.0"); diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java index 64729f6a3f41..3eafa6e21725 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java +++ b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java @@ -23,7 +23,8 @@ import com.intellij.ide.browsers.impl.DefaultUrlOpener; import com.intellij.openapi.components.*; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.WindowsRegistryUtil; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; import com.intellij.util.xmlb.XmlSerializer; @@ -34,8 +35,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.io.File; import java.util.ArrayList; -import java.util.EnumMap; import java.util.List; import java.util.Map; @@ -149,9 +150,7 @@ public class BrowsersConfiguration implements PersistentStateComponent } myBrowserToSettingsMap.put(browserFamily, new WebBrowserSettings(path, Boolean.parseBoolean(active), specificSettings)); } - catch (IllegalArgumentException e) { - // skip - } + catch (IllegalArgumentException ignored) { } } } @@ -191,6 +190,8 @@ public class BrowsersConfiguration implements PersistentStateComponent return ServiceManager.getService(BrowsersConfiguration.class); } + /** @deprecated use {@link DefaultUrlOpener} (to remove in IDEA 13) */ + @SuppressWarnings("unused") public static void launchBrowser(final @Nullable BrowserFamily family, @NotNull final String url) { if (family == null) { BrowserUtil.launchBrowser(url); @@ -230,7 +231,7 @@ public class BrowsersConfiguration implements PersistentStateComponent } @Nullable - public static BrowserFamily findFamilyByName(@Nullable String name) { + public BrowserFamily findFamilyByName(@Nullable String name) { for (BrowserFamily family : BrowserFamily.values()) { if (family.getName().equals(name)) { return family; @@ -239,49 +240,17 @@ public class BrowsersConfiguration implements PersistentStateComponent return null; } - /** - * Gets data from Windows registry, may take some time to run (up to ~300ms) - * - * @return Map[BrowserFamily -> "path to .exe"] - */ - @NotNull - public static EnumMap getWindowsBrowsersEXE() { - EnumMap map = new EnumMap(BrowserFamily.class); - if (SystemInfo.isWindows) { - List sections = WindowsRegistryUtil.readRegistryBranch("HKEY_LOCAL_MACHINE\\SOFTWARE\\Clients\\StartMenuInternet"); - for (String section : sections) { - BrowserFamily family = getFamily(section); - if (family == null) { - continue; //We ignore "unknown" browsers like Maxthon, RockMelt, SeaMonkey, Deepnet Explorer, Avant Browser etc. - } - String pathToExe = WindowsRegistryUtil.readRegistryDefault( - "HKLM\\SOFTWARE\\Clients\\StartMenuInternet\\" + section + "\\shell\\open\\command"); - if (pathToExe != null) { - map.put(family, pathToExe); + @Nullable + public BrowserFamily findFamilyByPath(@Nullable String path) { + if (!StringUtil.isEmptyOrSpaces(path)) { + String name = FileUtil.getNameWithoutExtension(new File(path).getName()); + for (BrowserFamily family : BrowserFamily.values()) { + if (name.equalsIgnoreCase(family.getExecutionPath())) { + return family; } } } - return map; - } - @Nullable - private static BrowserFamily getFamily(String registryName) { - registryName = registryName.toLowerCase(); - if (registryName.contains("firefox")) { - return BrowserFamily.FIREFOX; - } - if (registryName.contains("iexplore")) { - return BrowserFamily.EXPLORER; - } - if (registryName.contains("opera")) { - return BrowserFamily.OPERA; - } - if (registryName.contains("safari")) { - return BrowserFamily.SAFARI; - } - if (registryName.contains("google")) { - return BrowserFamily.CHROME; - } return null; } } diff --git a/xml/impl/src/com/intellij/ide/browsers/OpenFileInBrowserAction.java b/xml/impl/src/com/intellij/ide/browsers/OpenFileInBrowserAction.java index 2326b1ce4af2..c64ca67b1492 100644 --- a/xml/impl/src/com/intellij/ide/browsers/OpenFileInBrowserAction.java +++ b/xml/impl/src/com/intellij/ide/browsers/OpenFileInBrowserAction.java @@ -1,6 +1,22 @@ +/* + * Copyright 2000-2013 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.ide.browsers; import com.intellij.ide.BrowserUtil; +import com.intellij.ide.GeneralSettings; import com.intellij.ide.browsers.impl.WebBrowserServiceImpl; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; @@ -27,6 +43,7 @@ public class OpenFileInBrowserAction extends DumbAwareAction { final WebBrowserUrlProvider browserUrlProvider = WebBrowserServiceImpl.getProvider(file); final boolean isHtmlFile = HtmlUtil.isHtmlFile(file); presentation.setEnabled(browserUrlProvider != null || isHtmlFile); + String text = getTemplatePresentation().getText(); String description = getTemplatePresentation().getDescription(); @@ -46,10 +63,20 @@ public class OpenFileInBrowserAction extends DumbAwareAction { presentation.setText(text); presentation.setDescription(description); + + GeneralSettings settings = GeneralSettings.getInstance(); + if (!settings.isUseDefaultBrowser()) { + BrowsersConfiguration.BrowserFamily family = BrowsersConfiguration.getInstance().findFamilyByPath(settings.getBrowserPath()); + if (family != null) { + presentation.setIcon(family.getIcon()); + } + } + if (ActionPlaces.isPopupPlace(e.getPlace())) { presentation.setVisible(presentation.isEnabled()); } - } else { + } + else { presentation.setVisible(false); presentation.setEnabled(false); } diff --git a/xml/impl/src/com/intellij/ide/browsers/OpenUrlHyperlinkInfo.java b/xml/impl/src/com/intellij/ide/browsers/OpenUrlHyperlinkInfo.java index 880afc2a27ac..fe8fe0632216 100644 --- a/xml/impl/src/com/intellij/ide/browsers/OpenUrlHyperlinkInfo.java +++ b/xml/impl/src/com/intellij/ide/browsers/OpenUrlHyperlinkInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -85,7 +85,7 @@ public class OpenUrlHyperlinkInfo implements HyperlinkWithPopupMenuInfo { @Override public void actionPerformed(AnActionEvent e) { - BrowsersConfiguration.launchBrowser(myFamily, myUrl); + UrlOpener.launchBrowser(myFamily, myUrl); } } } diff --git a/xml/impl/src/com/intellij/ide/browsers/UrlOpener.java b/xml/impl/src/com/intellij/ide/browsers/UrlOpener.java index 36ba41ef2f54..62d59d4c9522 100644 --- a/xml/impl/src/com/intellij/ide/browsers/UrlOpener.java +++ b/xml/impl/src/com/intellij/ide/browsers/UrlOpener.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,26 @@ */ package com.intellij.ide.browsers; +import com.intellij.ide.BrowserUtil; import com.intellij.openapi.extensions.ExtensionPointName; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public abstract class UrlOpener { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("org.jetbrains.urlOpener"); - public abstract boolean openUrl(BrowsersConfiguration.BrowserFamily family, String url); + public static void launchBrowser(@Nullable BrowsersConfiguration.BrowserFamily family, @NotNull String url) { + if (family == null) { + BrowserUtil.launchBrowser(url); + } + else { + for (UrlOpener urlOpener : EP_NAME.getExtensions()) { + if (urlOpener.openUrl(family, url)) { + return; + } + } + } + } + + public abstract boolean openUrl(@NotNull BrowsersConfiguration.BrowserFamily family, String url); } diff --git a/xml/impl/src/com/intellij/ide/browsers/WebBrowsersPanel.java b/xml/impl/src/com/intellij/ide/browsers/WebBrowsersPanel.java index e5f53e7f8268..a7debbe2c2c2 100644 --- a/xml/impl/src/com/intellij/ide/browsers/WebBrowsersPanel.java +++ b/xml/impl/src/com/intellij/ide/browsers/WebBrowsersPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,14 @@ package com.intellij.ide.browsers; import com.intellij.ide.IdeBundle; +import com.intellij.ide.browsers.impl.BrowserConfigurationHelper; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.ui.IdeBorderFactory; import com.intellij.util.containers.HashMap; import com.intellij.xml.XmlBundle; @@ -32,7 +33,6 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.EnumMap; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -60,6 +60,8 @@ public class WebBrowsersPanel extends JPanel { createIndividualSettings(BrowsersConfiguration.BrowserFamily.SAFARI, mySettingsPanel); createIndividualSettings(BrowsersConfiguration.BrowserFamily.CHROME, mySettingsPanel); createIndividualSettings(BrowsersConfiguration.BrowserFamily.OPERA, mySettingsPanel); + + createPlatformSpecificAction(mySettingsPanel); } private void createIndividualSettings(@NotNull final BrowsersConfiguration.BrowserFamily family, final JPanel container) { @@ -125,53 +127,62 @@ public class WebBrowsersPanel extends JPanel { if (settings == null) { settings = family.createBrowserSpecificSettings(); } - - if (ShowSettingsUtil.getInstance().editConfigurable(mySettingsPanel, settings.createConfigurable())) { + if (settings != null && ShowSettingsUtil.getInstance().editConfigurable(mySettingsPanel, settings.createConfigurable())) { myConfiguration.updateBrowserSpecificSettings(family, settings); } } - public void applySettingsFromWindowsRegistry() { - if (!SystemInfo.isWindows) { - return; - } - ApplicationManager.getApplication() - .executeOnPooledThread(new SwingWorker, Void>() { + private void createPlatformSpecificAction(JPanel container) { + if (SystemInfo.isWindows) { + JButton registryButton = new JButton(XmlBundle.message("read.win.registry")); + registryButton.addActionListener(new ActionListener() { @Override - protected EnumMap doInBackground() throws Exception { - return BrowsersConfiguration.getWindowsBrowsersEXE(); - } - - @Override - protected void done() { - EnumMap map = null; - try { - map = get(); - } - catch (InterruptedException ignored) { - } - catch (ExecutionException ignored) { - } - if (myBrowserSettingsMap == null) { - return;//we are disposed - } - if (map != null && !map.isEmpty()) { - for (BrowsersConfiguration.BrowserFamily family : BrowsersConfiguration.BrowserFamily.values()) { - Pair pair = myBrowserSettingsMap.get(family); - String pathToExe = map.get(family); - if (pathToExe != null) { - pair.first.setSelected(true); - pair.second.setText(pathToExe); - } - else { - pair.first.setSelected(false); - } - } - } + public void actionPerformed(ActionEvent e) { + applySettingsFromWindowsRegistry(); } }); + + JPanel panel = new JPanel(new BorderLayout()); + panel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + panel.add(registryButton, BorderLayout.EAST); + container.add(panel); + } } + private void applySettingsFromWindowsRegistry() { + ApplicationManager.getApplication().executeOnPooledThread(new SwingWorker, Void>() { + @Override + protected Map doInBackground() throws Exception { + return BrowserConfigurationHelper.getBrowserPathsFromRegistry(); + } + + @Override + protected void done() { + Map map = null; + try { + map = get(); + } + catch (InterruptedException ignore) { } + catch (ExecutionException ignore) { } + + if (myBrowserSettingsMap == null || map == null || map.isEmpty()) { + return; + } + + for (BrowsersConfiguration.BrowserFamily family : BrowsersConfiguration.BrowserFamily.values()) { + Pair pair = myBrowserSettingsMap.get(family); + String pathToExe = map.get(family); + if (pathToExe != null) { + pair.first.setSelected(true); + pair.second.setText(pathToExe); + } + else { + pair.first.setSelected(false); + } + } + } + }); + } public void dispose() { myBrowserSettingsMap = null; diff --git a/xml/impl/src/com/intellij/ide/browsers/impl/BrowserConfigurationHelper.java b/xml/impl/src/com/intellij/ide/browsers/impl/BrowserConfigurationHelper.java new file mode 100644 index 000000000000..c534910d003e --- /dev/null +++ b/xml/impl/src/com/intellij/ide/browsers/impl/BrowserConfigurationHelper.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2013 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.ide.browsers.impl; + +import com.intellij.ide.browsers.BrowsersConfiguration; +import com.intellij.openapi.util.io.WindowsRegistryUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.EnumMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class BrowserConfigurationHelper { + private static final String START_MENU_KEY = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Clients\\StartMenuInternet"; + + /** + * Read data from Windows registry (may take some time to run). + */ + @NotNull + public static Map getBrowserPathsFromRegistry() { + Map map = + new EnumMap(BrowsersConfiguration.BrowserFamily.class); + + List sections = WindowsRegistryUtil.readRegistryBranch(START_MENU_KEY); + for (String section : sections) { + BrowsersConfiguration.BrowserFamily family = getFamily(section); + if (family != null) { + String pathToExe = WindowsRegistryUtil.readRegistryDefault(START_MENU_KEY + "\\" + section + "\\shell\\open\\command"); + if (pathToExe != null) { + map.put(family, pathToExe); + } + } + } + + return map; + } + + @Nullable + private static BrowsersConfiguration.BrowserFamily getFamily(String registryName) { + registryName = registryName.toLowerCase(); + for (BrowsersConfiguration.BrowserFamily family : BrowsersConfiguration.BrowserFamily.values()) { + if (registryName.contains(family.getName().toLowerCase(Locale.US))) { + return family; + } + } + + return null; + } +} diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsProviderImpl.java b/xml/impl/src/com/intellij/ide/browsers/impl/BrowserSettingsProviderImpl.java similarity index 74% rename from xml/impl/src/com/intellij/ide/browsers/BrowserSettingsProviderImpl.java rename to xml/impl/src/com/intellij/ide/browsers/impl/BrowserSettingsProviderImpl.java index e639095481a6..568a265d1a57 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsProviderImpl.java +++ b/xml/impl/src/com/intellij/ide/browsers/impl/BrowserSettingsProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.ide.browsers; +package com.intellij.ide.browsers.impl; import com.intellij.ide.BrowserSettingsProvider; -import com.intellij.openapi.diagnostic.Logger; +import com.intellij.ide.browsers.BrowsersConfiguration; +import com.intellij.ide.browsers.WebBrowsersPanel; import com.intellij.openapi.options.ConfigurationException; import org.jetbrains.annotations.NotNull; @@ -26,8 +27,6 @@ import javax.swing.*; * @author spleaner */ public class BrowserSettingsProviderImpl extends BrowserSettingsProvider { - private static final Logger LOG = Logger.getInstance("#com.intellij.ide.browsers.BrowserSettingsProviderImpl"); - private WebBrowsersPanel mySettingsPanel; private final BrowsersConfiguration myConfiguration; @@ -35,12 +34,6 @@ public class BrowserSettingsProviderImpl extends BrowserSettingsProvider { myConfiguration = configuration; } - @Override - public void applySettingsFromWindowsRegistry() { - if (mySettingsPanel != null) - mySettingsPanel.applySettingsFromWindowsRegistry(); - } - public JComponent createComponent() { if (mySettingsPanel == null) { mySettingsPanel = new WebBrowsersPanel(myConfiguration); @@ -50,17 +43,14 @@ public class BrowserSettingsProviderImpl extends BrowserSettingsProvider { } public boolean isModified() { - LOG.assertTrue(mySettingsPanel != null); return mySettingsPanel.isModified(); } public void apply() throws ConfigurationException { - LOG.assertTrue(mySettingsPanel != null); mySettingsPanel.apply(); } public void reset() { - LOG.assertTrue(mySettingsPanel != null); mySettingsPanel.reset(); } @@ -68,5 +58,4 @@ public class BrowserSettingsProviderImpl extends BrowserSettingsProvider { mySettingsPanel.dispose(); mySettingsPanel = null; } - } diff --git a/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java b/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java index ae37d74240d5..88f74b1c7e9d 100644 --- a/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java +++ b/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java @@ -41,7 +41,7 @@ public class DefaultUrlOpener extends UrlOpener { private static final Logger LOG = Logger.getInstance(DefaultUrlOpener.class); @Override - public boolean openUrl(BrowsersConfiguration.BrowserFamily family, @Nullable String url) { + public boolean openUrl(@NotNull BrowsersConfiguration.BrowserFamily family, @Nullable String url) { return launchBrowser(family, url, false); } diff --git a/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/DtdReferencesProvider.java b/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/DtdReferencesProvider.java index 4a3fcbaddf4a..cb816495b0e7 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/DtdReferencesProvider.java +++ b/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/DtdReferencesProvider.java @@ -138,6 +138,7 @@ public class DtdReferencesProvider extends PsiReferenceProvider { }; } + @NotNull public String getUnresolvedMessagePattern() { return XmlBundle.message("xml.dtd.unresolved.element.reference", getCanonicalText()); } @@ -259,6 +260,7 @@ public class DtdReferencesProvider extends PsiReferenceProvider { }; } + @NotNull public String getUnresolvedMessagePattern() { return XmlBundle.message("xml.dtd.unresolved.entity.reference", getCanonicalText()); } diff --git a/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/SchemaReferencesProvider.java b/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/SchemaReferencesProvider.java index b4c39f109269..d74ac1e4b2d7 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/SchemaReferencesProvider.java +++ b/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/SchemaReferencesProvider.java @@ -124,6 +124,7 @@ public class SchemaReferencesProvider extends PsiReferenceProvider { return false; } + @NotNull public String getUnresolvedMessagePattern() { return message; } diff --git a/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/URLReference.java b/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/URLReference.java index f5821112427f..e1a152905db9 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/URLReference.java +++ b/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/URLReference.java @@ -225,6 +225,7 @@ public class URLReference implements PsiReference, QuickFixProvider, EmptyResolv } } + @NotNull public String getUnresolvedMessagePattern() { return XmlErrorMessages.message(myIncorrectResourceMapped ? "registered.resource.is.not.recognized":"uri.is.not.registered"); } diff --git a/xml/impl/src/com/intellij/xml/util/AnchorReference.java b/xml/impl/src/com/intellij/xml/util/AnchorReference.java index 65e0c1a9522e..5bae0f65d68e 100644 --- a/xml/impl/src/com/intellij/xml/util/AnchorReference.java +++ b/xml/impl/src/com/intellij/xml/util/AnchorReference.java @@ -215,6 +215,7 @@ public class AnchorReference implements PsiReference, EmptyResolveMessageProvide return mySoft; } + @NotNull public String getUnresolvedMessagePattern() { final XmlFile xmlFile = getFile(); return xmlFile == null ? diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/PatternReference.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/PatternReference.java index c140344f3504..8aeab6059c17 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/PatternReference.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/PatternReference.java @@ -147,6 +147,7 @@ class PatternReference extends PsiReferenceBase.Poly implements Function return false; } + @NotNull public String getUnresolvedMessagePattern() { return "Unresolved pattern reference ''{0}''"; } diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/RncNameImpl.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/RncNameImpl.java index 26d350796265..6dc7ad54df8e 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/RncNameImpl.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/RncNameImpl.java @@ -135,6 +135,7 @@ public class RncNameImpl extends RncElementImpl implements RncName, PsiReference return "xsd".equals(prefix) || "xml".equals(prefix); } + @NotNull public String getUnresolvedMessagePattern() { return "Unresolved namespace prefix ''{0}''"; } diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/references/PrefixReferenceProvider.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/references/PrefixReferenceProvider.java index 27015b9ef39a..df9bcc8d5cf2 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/references/PrefixReferenceProvider.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/references/PrefixReferenceProvider.java @@ -118,6 +118,7 @@ public class PrefixReferenceProvider extends PsiReferenceProvider { return false; } + @NotNull public String getUnresolvedMessagePattern() { return "Undefined namespace prefix ''{0}''"; } diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/xml/dom/impl/DefinitionReference.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/xml/dom/impl/DefinitionReference.java index 2de2b477ffef..31b1950c9a8f 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/xml/dom/impl/DefinitionReference.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/xml/dom/impl/DefinitionReference.java @@ -153,6 +153,7 @@ public class DefinitionReference extends PsiReferenceBase.Poly