diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml index a73f663833c7..ec8ce0516fae 100644 --- a/.idea/uiDesigner.xml +++ b/.idea/uiDesigner.xml @@ -41,6 +41,9 @@ + + + diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpCapability.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpCapability.java new file mode 100644 index 000000000000..2a10039ba12b --- /dev/null +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpCapability.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2011 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.intellij.lang.regexp; + +/** + * @author yole + */ +public enum RegExpCapability { + XML_SCHEMA_MODE, + DANGLING_METACHARACTERS, + NESTED_CHARACTER_CLASSES, + OCTAL_NO_LEADING_ZERO, + OMIT_NUMBERS_IN_QUANTIFIERS, + COMMENT_MODE +} diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java index 17da2ae193b4..16ae1f322d28 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java @@ -30,7 +30,7 @@ import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Map; -class RegExpHighlighter extends SyntaxHighlighterBase { +public class RegExpHighlighter extends SyntaxHighlighterBase { private static final Map keys1; private static final Map keys2; diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpLexer.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpLexer.java index 82642e336963..c37f576a885b 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpLexer.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpLexer.java @@ -17,16 +17,20 @@ package org.intellij.lang.regexp; import com.intellij.lexer.FlexAdapter; +import java.util.EnumSet; + public class RegExpLexer extends FlexAdapter { private static final int COMMENT_MODE = 1 << 14; + private final EnumSet myCapabilities; - public RegExpLexer(boolean xmlSchemaMode, boolean allowDanglingMetacharacters) { - super(new _RegExLexer(xmlSchemaMode, allowDanglingMetacharacters)); - } + public RegExpLexer(EnumSet capabilities) { + super(new _RegExLexer(capabilities)); + myCapabilities = capabilities; + } public void start(CharSequence buffer, int startOffset, int endOffset, int initialState) { - getFlex().commentMode = (initialState & COMMENT_MODE) != 0; + getFlex().commentMode = (initialState & COMMENT_MODE) != 0 || myCapabilities.contains(RegExpCapability.COMMENT_MODE); super.start(buffer, startOffset, endOffset, initialState & ~COMMENT_MODE); } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java index d5d576b36df1..e0e06d940d10 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java @@ -23,17 +23,18 @@ import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.EnumSet; + @SuppressWarnings({"RedundantIfStatement"}) public class RegExpParser implements PsiParser { - private boolean myAllowDanglingMetacharacters; - private boolean myAllowOmitNumbersInQuantifiers; + private final EnumSet myCapabilities; - public void setAllowDanglingMetacharacters(boolean allowDanglingMetacharacters) { - myAllowDanglingMetacharacters = allowDanglingMetacharacters; + public RegExpParser() { + myCapabilities = EnumSet.noneOf(RegExpCapability.class); } - public void setAllowOmitNumbersInQuantifiers(boolean allowOmitNumbersInQuantifiers) { - myAllowOmitNumbersInQuantifiers = allowOmitNumbersInQuantifiers; + public RegExpParser(EnumSet capabilities) { + myCapabilities = capabilities; } @NotNull @@ -136,11 +137,11 @@ public class RegExpParser implements PsiParser { if (builder.getTokenType() == RegExpTT.LBRACE) { builder.advanceLexer(); boolean minOmitted = false; - if (builder.getTokenType() == RegExpTT.COMMA && myAllowOmitNumbersInQuantifiers) { + if (builder.getTokenType() == RegExpTT.COMMA && myCapabilities.contains(RegExpCapability.OMIT_NUMBERS_IN_QUANTIFIERS)) { minOmitted = true; builder.advanceLexer(); } - else if (builder.getTokenType() != RegExpTT.NUMBER && myAllowDanglingMetacharacters) { + else if (builder.getTokenType() != RegExpTT.NUMBER && myCapabilities.contains(RegExpCapability.DANGLING_METACHARACTERS)) { marker.done(RegExpTT.CHARACTER); return true; } @@ -432,7 +433,7 @@ public class RegExpParser implements PsiParser { marker.drop(); return parseClass(builder); } - else if (type == RegExpTT.LBRACE && myAllowDanglingMetacharacters) { + else if (type == RegExpTT.LBRACE && myCapabilities.contains(RegExpCapability.DANGLING_METACHARACTERS)) { builder.advanceLexer(); marker.done(RegExpElementTypes.CHAR); } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpParserDefinition.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpParserDefinition.java index 5b04474edb17..2148acb3bb13 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpParserDefinition.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpParserDefinition.java @@ -31,12 +31,14 @@ import com.intellij.psi.tree.TokenSet; import org.intellij.lang.regexp.psi.impl.*; import org.jetbrains.annotations.NotNull; +import java.util.EnumSet; + public class RegExpParserDefinition implements ParserDefinition { private static final TokenSet COMMENT_TOKENS = TokenSet.create(RegExpTT.COMMENT); @NotNull public Lexer createLexer(Project project) { - return new RegExpLexer(false, false); + return new RegExpLexer(EnumSet.of(RegExpCapability.NESTED_CHARACTER_CLASSES)); } public PsiParser createParser(Project project) { diff --git a/RegExpSupport/src/org/intellij/lang/regexp/_RegExLexer.java b/RegExpSupport/src/org/intellij/lang/regexp/_RegExLexer.java index adc8fd993c63..4381a383a338 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/_RegExLexer.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/_RegExLexer.java @@ -1,13 +1,13 @@ -/* The following code was generated by JFlex 1.4.3 on 01.06.10 15:51 */ +/* The following code was generated by JFlex 1.4.3 on 21.02.11 20:37 */ /* It's an automatically generated code. Do not modify it. */ package org.intellij.lang.regexp; import com.intellij.lexer.FlexLexer; -import com.intellij.psi.StringEscapesTokenTypes; import com.intellij.psi.tree.IElementType; - import java.util.LinkedList; +import java.util.EnumSet; +import com.intellij.psi.StringEscapesTokenTypes; // IDEADEV-11055 @SuppressWarnings({ "ALL", "SameParameterValue", "WeakerAccess", "SameReturnValue", "RedundantThrows", "UnusedDeclaration", "UnusedDeclaration" }) @@ -15,8 +15,8 @@ import java.util.LinkedList; /** * This class is a scanner generated by * JFlex 1.4.3 - * on 01.06.10 15:51 from the specification file - * C:/JetBrains/idea.branches/maia/tools/lexer/../../community/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex + * on 21.02.11 20:37 from the specification file + * C:/JetBrains/IDEA/tools/lexer/../../community/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex */ class _RegExLexer implements FlexLexer { /** initial size of the lookahead buffer */ @@ -24,17 +24,18 @@ class _RegExLexer implements FlexLexer { /** lexical states */ public static final int EMBRACED = 4; - public static final int PY_NAMED_GROUP_REF = 20; + public static final int CLASS1PY = 8; + public static final int PY_NAMED_GROUP_REF = 22; public static final int QUOTED = 2; - public static final int OPTIONS = 12; - public static final int PY_COND_REF = 22; + public static final int OPTIONS = 14; + public static final int PY_COND_REF = 24; public static final int YYINITIAL = 0; - public static final int NAMED_GROUP = 16; - public static final int CLASS2 = 8; + public static final int NAMED_GROUP = 18; + public static final int CLASS2 = 10; public static final int CLASS1 = 6; - public static final int COMMENT = 14; - public static final int QUOTED_NAMED_GROUP = 18; - public static final int PROP = 10; + public static final int COMMENT = 16; + public static final int QUOTED_NAMED_GROUP = 20; + public static final int PROP = 12; /** * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l @@ -44,7 +45,7 @@ class _RegExLexer implements FlexLexer { */ private static final int ZZ_LEXSTATE[] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, - 8, 8, 9, 9, 10, 10, 11, 11 + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12 }; /** @@ -130,20 +131,21 @@ class _RegExLexer implements FlexLexer { private static final int [] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = - "\6\0\1\1\1\2\4\0\1\3\1\4\1\5\1\6"+ + "\7\0\1\1\1\2\4\0\1\3\1\4\1\5\1\6"+ "\1\7\1\10\1\11\1\12\1\13\1\14\1\15\1\16"+ "\1\17\1\20\1\21\1\22\1\23\1\3\1\24\1\25"+ - "\1\26\1\27\1\30\1\31\1\32\1\33\1\34\1\3"+ - "\1\35\1\36\1\35\1\37\1\40\1\1\1\41\1\42"+ - "\1\2\1\43\1\44\1\45\1\46\1\47\1\50\1\51"+ - "\1\52\1\53\1\54\1\55\1\56\2\57\1\60\1\11"+ - "\1\61\1\62\1\63\1\64\1\65\1\66\1\0\1\67"+ - "\1\70\1\71\1\72\1\0\1\73\1\74\1\75\2\62"+ - "\2\63\1\76\1\77\1\100\1\101\1\0\1\74\1\62"+ - "\1\102\2\63\1\103\1\74\3\63\1\104"; + "\1\26\1\27\1\30\1\31\1\32\1\33\1\34\1\35"+ + "\1\11\1\36\1\3\1\37\1\40\1\37\1\41\1\42"+ + "\1\1\1\43\1\44\1\2\1\45\1\46\1\47\1\50"+ + "\1\0\1\51\1\52\1\53\1\54\1\55\1\56\1\57"+ + "\1\60\2\61\1\62\1\11\1\63\1\64\1\65\1\52"+ + "\1\66\1\67\1\70\1\71\1\72\1\0\1\73\1\74"+ + "\1\75\1\76\1\0\1\77\1\100\1\101\1\102\2\64"+ + "\2\65\1\52\1\103\1\104\1\105\1\106\1\0\1\101"+ + "\1\64\1\107\2\65\1\110\1\111\1\101\3\65\1\112"; private static int [] zzUnpackAction() { - int [] result = new int[100]; + int [] result = new int[111]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -169,21 +171,22 @@ class _RegExLexer implements FlexLexer { private static final String ZZ_ROWMAP_PACKED_0 = "\0\0\0\63\0\146\0\231\0\314\0\377\0\u0132\0\u0165"+ - "\0\u0198\0\u01cb\0\u01fe\0\u0231\0\u0264\0\u0264\0\u0297\0\u0264"+ - "\0\u0264\0\u02ca\0\u02fd\0\u0264\0\u0264\0\u0264\0\u0264\0\u0264"+ - "\0\u0264\0\u0264\0\u0264\0\u0264\0\u0264\0\u0330\0\u0264\0\u0363"+ - "\0\u0264\0\u0396\0\u0264\0\u0264\0\u0264\0\u0264\0\u0264\0\u03c9"+ - "\0\u0264\0\u0264\0\u02ca\0\u0264\0\u0264\0\u03fc\0\u042f\0\u0264"+ - "\0\u0264\0\u0264\0\u0264\0\u0462\0\u0264\0\u0264\0\u0495\0\u04c8"+ - "\0\u0264\0\u0264\0\u0264\0\u0264\0\u0264\0\u0264\0\u04fb\0\u0264"+ - "\0\u0264\0\u0264\0\u052e\0\u0561\0\u0264\0\u0264\0\u0264\0\u0594"+ - "\0\u0264\0\u0264\0\u0264\0\u05c7\0\u05fa\0\u0264\0\u062d\0\u0264"+ - "\0\u0660\0\u0693\0\u06c6\0\u06f9\0\u0264\0\u0264\0\u0264\0\u0264"+ - "\0\u072c\0\u075f\0\u0264\0\u0264\0\u0792\0\u07c5\0\u0264\0\u0264"+ - "\0\u07f8\0\u082b\0\u0264\0\u0264"; + "\0\u0198\0\u01cb\0\u01fe\0\u0231\0\u0264\0\u0297\0\u0297\0\u02ca"+ + "\0\u0297\0\u0297\0\u02fd\0\u0330\0\u0297\0\u0297\0\u0297\0\u0297"+ + "\0\u0297\0\u0297\0\u0297\0\u0297\0\u0297\0\u0297\0\u0363\0\u0297"+ + "\0\u0396\0\u0297\0\u03c9\0\u0297\0\u0297\0\u0297\0\u0297\0\u03fc"+ + "\0\u0297\0\u042f\0\u0297\0\u0462\0\u0297\0\u0297\0\u02fd\0\u0297"+ + "\0\u0297\0\u0495\0\u04c8\0\u0297\0\u0297\0\u0297\0\u0297\0\u04fb"+ + "\0\u0297\0\u052e\0\u0297\0\u0561\0\u0594\0\u0297\0\u0297\0\u0297"+ + "\0\u0297\0\u0297\0\u0297\0\u05c7\0\u0297\0\u0297\0\u0297\0\u05fa"+ + "\0\u062d\0\u0660\0\u0297\0\u0297\0\u0297\0\u0297\0\u0297\0\u0693"+ + "\0\u0297\0\u0297\0\u0297\0\u06c6\0\u06f9\0\u0297\0\u0297\0\u072c"+ + "\0\u0297\0\u075f\0\u0792\0\u07c5\0\u07f8\0\u082b\0\u0297\0\u0297"+ + "\0\u0297\0\u0297\0\u085e\0\u0891\0\u0297\0\u0297\0\u08c4\0\u08f7"+ + "\0\u0561\0\u0297\0\u0297\0\u092a\0\u095d\0\u0297\0\u0297"; private static int [] zzUnpackRowMap() { - int [] result = new int[100]; + int [] result = new int[111]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -206,47 +209,53 @@ class _RegExLexer implements FlexLexer { private static final int [] ZZ_TRANS = zzUnpackTrans(); private static final String ZZ_TRANS_PACKED_0 = - "\3\15\1\16\1\17\1\20\1\21\1\15\1\22\1\15"+ - "\1\23\1\24\1\25\1\26\1\27\1\30\1\31\1\32"+ - "\21\15\1\33\1\15\1\34\4\15\1\24\5\15\1\35"+ - "\1\15\1\24\12\15\1\36\1\0\47\15\1\37\2\40"+ - "\4\37\1\41\12\37\20\42\1\40\1\37\1\42\2\37"+ - "\1\40\1\43\12\37\11\44\1\45\1\44\1\0\47\44"+ - "\6\15\1\21\1\15\1\22\1\46\1\23\1\47\1\25"+ - "\26\15\1\33\5\15\1\50\1\47\7\15\1\47\6\51"+ - "\1\52\1\51\1\53\1\51\1\23\50\51\5\54\1\55"+ - "\14\54\20\56\1\54\1\57\1\56\6\54\1\60\7\54"+ - "\13\10\1\61\46\10\1\61\22\54\20\42\2\54\1\42"+ - "\7\54\1\62\30\54\20\42\2\54\1\42\14\54\1\63"+ - "\6\54\1\55\14\54\20\42\2\54\1\42\17\54\2\40"+ - "\2\54\1\55\14\54\20\42\1\40\1\54\1\42\2\54"+ - "\1\40\13\54\101\0\1\64\55\0\1\65\51\0\1\66"+ - "\1\67\1\70\4\71\1\66\1\71\1\66\1\71\1\72"+ - "\6\71\2\73\2\74\2\75\1\76\1\77\1\76\2\100"+ - "\1\101\1\102\1\101\1\103\1\104\1\67\1\71\1\101"+ - "\1\72\4\66\1\72\7\66\1\72\37\0\1\105\24\0"+ - "\2\40\37\0\1\40\4\0\1\40\14\0\2\42\17\0"+ - "\21\42\1\0\1\42\1\0\2\42\64\0\1\106\33\0"+ - "\20\56\2\0\1\56\40\0\20\57\2\0\1\57\22\0"+ - "\1\107\27\0\1\110\16\0\2\111\1\112\1\113\1\114"+ - "\1\115\1\116\2\0\2\67\37\0\1\67\22\0\1\117"+ - "\37\0\1\117\20\0\63\120\1\121\2\122\20\121\2\122"+ - "\2\121\3\122\3\121\1\122\1\121\1\122\2\121\1\122"+ - "\20\121\1\123\2\124\20\123\2\124\2\123\3\124\3\123"+ - "\1\124\1\123\1\124\2\123\1\124\20\123\55\0\1\125"+ - "\1\0\1\126\60\0\1\127\1\130\4\0\5\131\1\0"+ - "\55\131\2\0\1\132\37\0\1\132\20\0\64\133\2\134"+ - "\20\133\2\134\2\133\3\134\3\133\1\134\1\133\1\134"+ - "\2\133\1\134\20\133\64\135\2\136\20\135\2\136\2\135"+ - "\3\136\3\135\1\136\1\135\1\136\2\135\1\136\20\135"+ - "\5\131\1\137\55\131\2\0\1\140\37\0\1\140\20\0"+ - "\64\141\2\142\20\141\2\142\2\141\3\142\3\141\1\142"+ - "\1\141\1\142\2\141\1\142\20\141\64\143\2\144\20\143"+ - "\2\144\2\143\3\144\3\143\1\144\1\143\1\144\2\143"+ - "\1\144\20\143"; + "\3\16\1\17\1\20\1\21\1\22\1\16\1\23\1\16"+ + "\1\24\1\25\1\26\1\27\1\30\1\31\1\32\1\33"+ + "\21\16\1\34\1\16\1\35\4\16\1\25\5\16\1\36"+ + "\1\16\1\25\12\16\1\37\1\0\47\16\1\40\2\41"+ + "\4\40\1\42\12\40\20\43\1\41\1\40\1\43\2\40"+ + "\1\41\1\44\12\40\11\45\1\46\1\45\1\0\62\45"+ + "\1\0\1\47\46\45\6\16\1\22\1\16\1\50\1\51"+ + "\1\52\1\53\1\26\26\16\1\34\5\16\1\54\1\53"+ + "\7\16\1\53\6\55\1\56\1\55\1\57\1\55\1\24"+ + "\50\55\5\60\1\61\14\60\20\62\1\60\1\63\1\62"+ + "\6\60\1\64\7\60\13\11\1\65\46\11\1\65\22\60"+ + "\20\43\2\60\1\43\7\60\1\66\30\60\20\43\2\60"+ + "\1\43\14\60\1\67\6\60\1\61\14\60\20\43\2\60"+ + "\1\43\17\60\2\41\2\60\1\61\14\60\20\43\1\41"+ + "\1\60\1\43\2\60\1\41\13\60\101\0\1\70\55\0"+ + "\1\71\2\0\1\72\46\0\1\73\1\74\1\75\4\76"+ + "\1\73\1\76\1\73\1\76\1\77\6\76\2\100\2\101"+ + "\2\102\1\103\1\104\1\103\2\105\1\106\1\107\1\106"+ + "\1\110\1\111\1\112\1\76\1\106\1\77\4\73\1\77"+ + "\7\73\1\77\37\0\1\113\24\0\2\41\37\0\1\41"+ + "\4\0\1\41\14\0\2\43\17\0\21\43\1\0\1\43"+ + "\1\0\2\43\24\0\1\114\2\0\1\72\46\0\1\73"+ + "\1\74\1\75\4\76\1\73\1\76\1\115\1\76\1\77"+ + "\6\76\2\100\2\101\2\102\1\103\1\104\1\103\2\105"+ + "\1\106\1\107\1\106\1\110\1\111\1\112\1\76\1\106"+ + "\1\77\4\73\1\77\7\73\1\77\51\0\1\116\33\0"+ + "\20\62\2\0\1\62\40\0\20\63\2\0\1\63\22\0"+ + "\1\117\27\0\1\120\16\0\2\121\1\122\1\123\1\124"+ + "\1\125\1\126\12\0\1\127\52\0\2\74\37\0\1\74"+ + "\22\0\1\130\37\0\1\130\20\0\63\131\1\132\2\133"+ + "\20\132\2\133\2\132\3\133\3\132\1\133\1\132\1\133"+ + "\2\132\1\133\20\132\1\134\2\135\20\134\2\135\2\134"+ + "\3\135\3\134\1\135\1\134\1\135\2\134\1\135\20\134"+ + "\1\0\1\74\1\136\37\0\1\136\75\0\1\137\1\0"+ + "\1\140\60\0\1\141\1\142\4\0\5\143\1\0\55\143"+ + "\2\0\1\144\37\0\1\144\20\0\64\145\2\146\20\145"+ + "\2\146\2\145\3\146\3\145\1\146\1\145\1\146\2\145"+ + "\1\146\20\145\64\147\2\150\20\147\2\150\2\147\3\150"+ + "\3\147\1\150\1\147\1\150\2\147\1\150\20\147\1\0"+ + "\1\74\1\151\37\0\1\151\20\0\5\143\1\152\55\143"+ + "\2\0\1\153\37\0\1\153\20\0\64\154\2\155\20\154"+ + "\2\155\2\154\3\155\3\154\1\155\1\154\1\155\2\154"+ + "\1\155\20\154\64\156\2\157\20\156\2\157\2\156\3\157"+ + "\3\156\1\157\1\156\1\157\2\156\1\157\20\156"; private static int [] zzUnpackTrans() { - int [] result = new int[2142]; + int [] result = new int[2448]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -287,15 +296,16 @@ class _RegExLexer implements FlexLexer { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\6\0\2\1\4\0\2\11\1\1\2\11\2\1\12\11"+ - "\1\1\1\11\1\1\1\11\1\1\5\11\1\1\2\11"+ - "\1\1\2\11\2\1\4\11\1\1\2\11\2\1\6\11"+ - "\1\1\3\11\2\1\3\11\1\0\3\11\1\1\1\0"+ - "\1\11\1\1\1\11\4\1\4\11\1\0\1\1\2\11"+ - "\2\1\2\11\2\1\2\11"; + "\7\0\2\1\4\0\2\11\1\1\2\11\2\1\12\11"+ + "\1\1\1\11\1\1\1\11\1\1\4\11\1\1\1\11"+ + "\1\1\1\11\1\1\2\11\1\1\2\11\2\1\4\11"+ + "\1\1\1\11\1\0\1\11\2\1\6\11\1\1\3\11"+ + "\3\1\5\11\1\0\3\11\1\1\1\0\2\11\1\1"+ + "\1\11\5\1\4\11\1\0\1\1\2\11\3\1\2\11"+ + "\2\1\2\11"; private static int [] zzUnpackAttribute() { - int [] result = new int[100]; + int [] result = new int[111]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -358,15 +368,21 @@ class _RegExLexer implements FlexLexer { private final LinkedList states = new LinkedList(); // This was an idea to use the regex implementation for XML schema regexes (which use a slightly different syntax) - // as well, but is currently unfinished as it requires to tweak more places than just the lexer. + // as well, but is currently unfinished as it requires to tweak more places than just the lexer. private boolean xmlSchemaMode; - private boolean allowDanglingMetacharacters; - _RegExLexer(boolean xmlSchemaMode, boolean allowDanglingMetacharacters) { + private boolean allowDanglingMetacharacters; + private boolean allowNestedCharacterClasses; + private boolean allowOctalNoLeadingZero; + + _RegExLexer(EnumSet capabilities) { this((java.io.Reader)null); - this.xmlSchemaMode = xmlSchemaMode; - this.allowDanglingMetacharacters = allowDanglingMetacharacters; + this.xmlSchemaMode = capabilities.contains(RegExpCapability.XML_SCHEMA_MODE); + this.allowDanglingMetacharacters = capabilities.contains(RegExpCapability.DANGLING_METACHARACTERS); + this.allowNestedCharacterClasses = capabilities.contains(RegExpCapability.NESTED_CHARACTER_CLASSES); + this.allowOctalNoLeadingZero = capabilities.contains(RegExpCapability.OCTAL_NO_LEADING_ZERO); + this.commentMode = capabilities.contains(RegExpCapability.COMMENT_MODE); } private void yypushstate(int state) { @@ -636,272 +652,219 @@ class _RegExLexer implements FlexLexer { zzMarkedPos = zzMarkedPosL; switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { - case 7: - { if (yystate() != CLASS2) yypushstate(EMBRACED); return RegExpTT.LBRACE; - } - case 69: break; - case 6: - { return RegExpTT.GROUP_END; - } - case 70: break; - case 38: - // lookahead expression with fixed base length - zzMarkedPos = zzStartRead + 1; - { yypushstate(CLASS1); return RegExpTT.CLASS_BEGIN; - } - case 71: break; - case 14: - { return RegExpTT.STAR; - } - case 72: break; - case 42: - { return RegExpTT.ESC_CHARACTER; - } - case 73: break; - case 28: - { return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.ESC_CHARACTER; - } - case 74: break; - case 43: - { return commentMode ? RegExpTT.CHARACTER : RegExpTT.REDUNDANT_ESCAPE; + case 74: + { return RegExpTT.UNICODE_CHAR; } case 75: break; - case 39: - { return RegExpTT.REDUNDANT_ESCAPE; + case 7: + { if (yystate() != CLASS2) yypushstate(EMBRACED); return RegExpTT.LBRACE; } case 76: break; case 24: { return RegExpTT.COMMA; } case 77: break; - case 58: - { yybegin(NAMED_GROUP); return RegExpTT.RUBY_NAMED_GROUP; - } - case 78: break; - case 64: - { return RegExpTT.POS_LOOKBEHIND; - } - case 79: break; - case 41: - { return RegExpTT.BAD_OCT_VALUE; - } - case 80: break; - case 10: - { return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CTRL_CHARACTER; - } - case 81: break; - case 30: - { yypopstate(); yypushstate(EMBRACED); return RegExpTT.LBRACE; - } - case 82: break; - case 51: - { return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN; - } - case 83: break; - case 65: - { return RegExpTT.NEG_LOOKBEHIND; - } - case 84: break; - case 68: - { return RegExpTT.UNICODE_CHAR; - } - case 85: break; - case 61: - { if (xmlSchemaMode) { yypushback(1); return RegExpTT.CHAR_CLASS; } else return RegExpTT.CTRL; - } - case 86: break; - case 37: - { yybegin(OPTIONS); return RegExpTT.SET_OPTIONS; - } - case 87: break; - case 12: - { return RegExpTT.DOLLAR; - } - case 88: break; - case 52: - { yypopstate(); return RegExpTT.QUOTE_END; - } - case 89: break; - case 56: + case 60: { return RegExpTT.POS_LOOKAHEAD; } - case 90: break; - case 22: - { yypopstate(); return RegExpTT.RBRACE; - } - case 91: break; - case 3: - { return RegExpTT.CHARACTER; - } - case 92: break; - case 57: - { return RegExpTT.NEG_LOOKAHEAD; - } - case 93: break; - case 44: - { return RegExpTT.ESC_CTRL_CHARACTER; - } - case 94: break; - case 23: - { return RegExpTT.NAME; - } - case 95: break; - case 53: - { return RegExpTT.ANDAND; - } - case 96: break; - case 13: - { return RegExpTT.QUEST; - } - case 97: break; - case 46: - { return RegExpTT.CHAR_CLASS; - } - case 98: break; - case 17: - { return RegExpTT.MINUS; - } - case 99: break; - case 67: + case 78: break; + case 73: { return RegExpTT.COMMENT; } - case 100: break; - case 40: - { return yystate() != CLASS2 ? RegExpTT.BACKREF : RegExpTT.ESC_CHARACTER; - } - case 101: break; - case 16: - { return RegExpTT.UNION; - } - case 102: break; - case 47: - { if (xmlSchemaMode) return RegExpTT.CHAR_CLASS; else return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN; - } - case 103: break; - case 60: - { return RegExpTT.OCT_CHAR; - } - case 104: break; - case 4: - { return RegExpTT.DOT; - } - case 105: break; - case 32: - { yybegin(YYINITIAL); return RegExpTT.GROUP_END; - } - case 106: break; - case 21: - { return RegExpTT.NUMBER; - } - case 107: break; - case 35: - { yybegin(YYINITIAL); return RegExpTT.GT; - } - case 108: break; - case 59: - { yybegin(QUOTED_NAMED_GROUP); return RegExpTT.RUBY_QUOTED_NAMED_GROUP; - } - case 109: break; - case 54: - { yybegin(PY_COND_REF); return RegExpTT.PYTHON_COND_REF; - } - case 110: break; - case 48: - { yypushstate(PROP); return RegExpTT.PROPERTY; - } - case 111: break; - case 18: - { return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CHARACTER; - } - case 112: break; - case 33: - { handleOptions(); return RegExpTT.OPTIONS_OFF; - } - case 113: break; - case 34: - { yybegin(YYINITIAL); return RegExpTT.COLON; - } - case 114: break; - case 25: - { assert false : yytext(); - } - case 115: break; - case 62: - { yybegin(PY_NAMED_GROUP_REF); return RegExpTT.PYTHON_NAMED_GROUP_REF; - } - case 116: break; - case 27: - { yypopstate(); return RegExpTT.CLASS_END; - } - case 117: break; - case 11: - { return RegExpTT.CARET; - } - case 118: break; - case 1: - { handleOptions(); return RegExpTT.OPTIONS_ON; - } - case 119: break; - case 29: - { yypopstate(); yypushback(1); - } - case 120: break; - case 45: - { return yystate() != CLASS2 ? RegExpTT.BOUNDARY : RegExpTT.ESC_CHARACTER; - } - case 121: break; - case 63: + case 79: break; + case 68: { yybegin(NAMED_GROUP); return RegExpTT.PYTHON_NAMED_GROUP; } - case 122: break; - case 19: - { if (commentMode) { yypushstate(COMMENT); return RegExpTT.COMMENT; } else return RegExpTT.CHARACTER; + case 80: break; + case 14: + { return RegExpTT.STAR; } - case 123: break; - case 66: - { return RegExpTT.HEX_CHAR; + case 81: break; + case 58: + { yybegin(PY_COND_REF); return RegExpTT.PYTHON_COND_REF; } - case 124: break; + case 82: break; + case 48: + { return RegExpTT.CHAR_CLASS; + } + case 83: break; + case 35: + { handleOptions(); return RegExpTT.OPTIONS_OFF; + } + case 84: break; + case 54: + { yypopstate(); return RegExpTT.QUOTE_END; + } + case 85: break; + case 34: + { yybegin(YYINITIAL); return RegExpTT.GROUP_END; + } + case 86: break; case 5: { return RegExpTT.GROUP_BEGIN; } - case 125: break; - case 8: - { yypushstate(CLASS2); return RegExpTT.CLASS_BEGIN; + case 87: break; + case 36: + { yybegin(YYINITIAL); return RegExpTT.COLON; } - case 126: break; - case 55: + case 88: break; + case 6: + { return RegExpTT.GROUP_END; + } + case 89: break; + case 25: + { assert false : yytext(); + } + case 90: break; + case 18: + { return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CHARACTER; + } + case 91: break; + case 45: + { return commentMode ? RegExpTT.CHARACTER : RegExpTT.REDUNDANT_ESCAPE; + } + case 92: break; + case 23: + { return RegExpTT.NAME; + } + case 93: break; + case 72: + { if (allowOctalNoLeadingZero) return RegExpTT.OCT_CHAR; + return yystate() != CLASS2 ? RegExpTT.BACKREF : RegExpTT.ESC_CHARACTER; + } + case 94: break; + case 29: + { yypopstate(); return RegExpTT.CLASS_END; + } + case 95: break; + case 33: + { yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER; + } + case 96: break; + case 51: + { yypushstate(QUOTED); return RegExpTT.QUOTE_BEGIN; + } + case 97: break; + case 21: + { return RegExpTT.NUMBER; + } + case 98: break; + case 4: + { return RegExpTT.DOT; + } + case 99: break; + case 70: + { return RegExpTT.NEG_LOOKBEHIND; + } + case 100: break; + case 40: + // lookahead expression with fixed base length + zzMarkedPos = zzStartRead + 1; + { yypushstate(CLASS1); + return RegExpTT.CLASS_BEGIN; + } + case 101: break; + case 61: + { return RegExpTT.NEG_LOOKAHEAD; + } + case 102: break; + case 10: + { return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CTRL_CHARACTER; + } + case 103: break; + case 59: { return RegExpTT.NON_CAPT_GROUP; } - case 127: break; - case 9: - { return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN; + case 104: break; + case 63: + { yybegin(QUOTED_NAMED_GROUP); return RegExpTT.RUBY_QUOTED_NAMED_GROUP; } - case 128: break; - case 36: - { yybegin(YYINITIAL); return RegExpTT.QUOTE; + case 105: break; + case 28: + { if (allowNestedCharacterClasses) { + yypushstate(CLASS2); + return RegExpTT.CLASS_BEGIN; + } + return RegExpTT.CHARACTER; } - case 129: break; + case 106: break; + case 19: + { if (commentMode) { yypushstate(COMMENT); return RegExpTT.COMMENT; } else return RegExpTT.CHARACTER; + } + case 107: break; case 50: - { return RegExpTT.BAD_HEX_VALUE; + { yypushstate(PROP); return RegExpTT.PROPERTY; } - case 130: break; + case 108: break; + case 8: + { yypushstate(CLASS2); + return RegExpTT.CLASS_BEGIN; + } + case 109: break; + case 69: + { return RegExpTT.POS_LOOKBEHIND; + } + case 110: break; + case 42: + { return yystate() != CLASS2 ? RegExpTT.BACKREF : RegExpTT.ESC_CHARACTER; + } + case 111: break; + case 71: + { return RegExpTT.HEX_CHAR; + } + case 112: break; + case 1: + { handleOptions(); return RegExpTT.OPTIONS_ON; + } + case 113: break; + case 57: + { return allowNestedCharacterClasses ? RegExpTT.ANDAND : RegExpTT.CHARACTER; + } + case 114: break; case 2: { yypopstate(); return RegExpTT.COMMENT; } - case 131: break; - case 49: - { yypushstate(QUOTED); return RegExpTT.QUOTE_BEGIN; + case 115: break; + case 17: + { return RegExpTT.MINUS; } - case 132: break; - case 26: - { yybegin(CLASS2); return RegExpTT.CHARACTER; + case 116: break; + case 46: + { return RegExpTT.ESC_CTRL_CHARACTER; } - case 133: break; + case 117: break; + case 32: + { yypopstate(); yypushstate(EMBRACED); return RegExpTT.LBRACE; + } + case 118: break; + case 13: + { return RegExpTT.QUEST; + } + case 119: break; case 15: { return RegExpTT.PLUS; } - case 134: break; + case 120: break; + case 65: + { return RegExpTT.OCT_CHAR; + } + case 121: break; + case 38: + { yybegin(YYINITIAL); return RegExpTT.QUOTE; + } + case 122: break; + case 64: + // lookahead expression with fixed base length + zzMarkedPos = zzStartRead + 1; + { if (!allowNestedCharacterClasses) { + yypushstate(CLASS1PY); + } + else { + yypushstate(CLASS2); + } + return RegExpTT.CLASS_BEGIN; + } + case 123: break; case 20: { if (allowDanglingMetacharacters) { yypopstate(); yypushback(1); @@ -909,11 +872,110 @@ class _RegExLexer implements FlexLexer { return RegExpTT.BAD_CHARACTER; } } - case 135: break; + case 124: break; case 31: - { yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER; + { yypopstate(); yypushback(1); + } + case 125: break; + case 27: + { yybegin(CLASS1); return RegExpTT.CARET; + } + case 126: break; + case 55: + // lookahead expression with fixed base length + zzMarkedPos = zzStartRead + 1; + { if (allowNestedCharacterClasses) { + yypushstate(CLASS1); + return RegExpTT.CLASS_BEGIN; + } + return RegExpTT.CHARACTER; + } + case 127: break; + case 56: + { if (!allowNestedCharacterClasses) return RegExpTT.CHARACTER; + return RegExpTT.REDUNDANT_ESCAPE; + } + case 128: break; + case 37: + { yybegin(YYINITIAL); return RegExpTT.GT; + } + case 129: break; + case 67: + { yybegin(PY_NAMED_GROUP_REF); return RegExpTT.PYTHON_NAMED_GROUP_REF; + } + case 130: break; + case 16: + { return RegExpTT.UNION; + } + case 131: break; + case 3: + { return RegExpTT.CHARACTER; + } + case 132: break; + case 62: + { yybegin(NAMED_GROUP); return RegExpTT.RUBY_NAMED_GROUP; + } + case 133: break; + case 39: + { yybegin(OPTIONS); return RegExpTT.SET_OPTIONS; + } + case 134: break; + case 26: + { yybegin(CLASS2); return RegExpTT.CHARACTER; + } + case 135: break; + case 66: + { if (xmlSchemaMode) { yypushback(1); return RegExpTT.CHAR_CLASS; } else return RegExpTT.CTRL; } case 136: break; + case 30: + { return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.ESC_CHARACTER; + } + case 137: break; + case 12: + { return RegExpTT.DOLLAR; + } + case 138: break; + case 49: + { if (xmlSchemaMode) return RegExpTT.CHAR_CLASS; else return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN; + } + case 139: break; + case 41: + { return RegExpTT.REDUNDANT_ESCAPE; + } + case 140: break; + case 47: + { return yystate() != CLASS2 ? RegExpTT.BOUNDARY : RegExpTT.ESC_CHARACTER; + } + case 141: break; + case 22: + { yypopstate(); return RegExpTT.RBRACE; + } + case 142: break; + case 53: + { return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN; + } + case 143: break; + case 43: + { return RegExpTT.BAD_OCT_VALUE; + } + case 144: break; + case 52: + { return RegExpTT.BAD_HEX_VALUE; + } + case 145: break; + case 9: + { return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN; + } + case 146: break; + case 11: + { return RegExpTT.CARET; + } + case 147: break; + case 44: + { return RegExpTT.ESC_CHARACTER; + } + case 148: break; default: if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { zzAtEOF = true; diff --git a/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex b/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex index 5269feebd791..e42ae56cdef0 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex +++ b/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex @@ -4,6 +4,7 @@ package org.intellij.lang.regexp; import com.intellij.lexer.FlexLexer; import com.intellij.psi.tree.IElementType; import java.util.LinkedList; +import java.util.EnumSet; import com.intellij.psi.StringEscapesTokenTypes; // IDEADEV-11055 @@ -23,15 +24,21 @@ import com.intellij.psi.StringEscapesTokenTypes; private final LinkedList states = new LinkedList(); // This was an idea to use the regex implementation for XML schema regexes (which use a slightly different syntax) - // as well, but is currently unfinished as it requires to tweak more places than just the lexer. + // as well, but is currently unfinished as it requires to tweak more places than just the lexer. private boolean xmlSchemaMode; - private boolean allowDanglingMetacharacters; - _RegExLexer(boolean xmlSchemaMode, boolean allowDanglingMetacharacters) { + private boolean allowDanglingMetacharacters; + private boolean allowNestedCharacterClasses; + private boolean allowOctalNoLeadingZero; + + _RegExLexer(EnumSet capabilities) { this((java.io.Reader)null); - this.xmlSchemaMode = xmlSchemaMode; - this.allowDanglingMetacharacters = allowDanglingMetacharacters; + this.xmlSchemaMode = capabilities.contains(RegExpCapability.XML_SCHEMA_MODE); + this.allowDanglingMetacharacters = capabilities.contains(RegExpCapability.DANGLING_METACHARACTERS); + this.allowNestedCharacterClasses = capabilities.contains(RegExpCapability.NESTED_CHARACTER_CLASSES); + this.allowOctalNoLeadingZero = capabilities.contains(RegExpCapability.OCTAL_NO_LEADING_ZERO); + this.commentMode = capabilities.contains(RegExpCapability.COMMENT_MODE); } private void yypushstate(int state) { @@ -58,6 +65,7 @@ import com.intellij.psi.StringEscapesTokenTypes; %xstate QUOTED %xstate EMBRACED %xstate CLASS1 +%xstate CLASS1PY %state CLASS2 %state PROP %xstate OPTIONS @@ -133,7 +141,10 @@ HEX_CHAR=[0-9a-fA-F] So, for 100% compatibility, backrefs > 9 should be resolved by the parser, but I'm not sure if it's worth the effort - at least not atm. */ - +{ESCAPE} [0-7]{3} { if (allowOctalNoLeadingZero) return RegExpTT.OCT_CHAR; + return yystate() != CLASS2 ? RegExpTT.BACKREF : RegExpTT.ESC_CHARACTER; + } + {ESCAPE} {DIGITS} { return yystate() != CLASS2 ? RegExpTT.BACKREF : RegExpTT.ESC_CHARACTER; } {ESCAPE} "-" { return RegExpTT.ESC_CHARACTER; } @@ -146,7 +157,15 @@ HEX_CHAR=[0-9a-fA-F] {ESCAPE} [:letter:] { return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN; } {ESCAPE} [\n\b\t\r\f ] { return commentMode ? RegExpTT.CHARACTER : RegExpTT.REDUNDANT_ESCAPE; } + + { + {ESCAPE} {RBRACKET} { if (!allowNestedCharacterClasses) return RegExpTT.CHARACTER; + return RegExpTT.REDUNDANT_ESCAPE; } +} + {ESCAPE} {ANY} { return RegExpTT.REDUNDANT_ESCAPE; } + + {ESCAPE} { return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN; } { @@ -175,8 +194,37 @@ HEX_CHAR=[0-9a-fA-F] "-" { return RegExpTT.MINUS; } "^" { return RegExpTT.CARET; } -{LBRACKET} / {RBRACKET} { yypushstate(CLASS1); return RegExpTT.CLASS_BEGIN; } -{LBRACKET} { yypushstate(CLASS2); return RegExpTT.CLASS_BEGIN; } + { + {LBRACKET} { if (allowNestedCharacterClasses) { + yypushstate(CLASS2); + return RegExpTT.CLASS_BEGIN; + } + return RegExpTT.CHARACTER; + } + + {LBRACKET} / {RBRACKET} { if (allowNestedCharacterClasses) { + yypushstate(CLASS1); + return RegExpTT.CLASS_BEGIN; + } + return RegExpTT.CHARACTER; + } +} + +{LBRACKET} / {RBRACKET} { yypushstate(CLASS1); + return RegExpTT.CLASS_BEGIN; } + +/* Python understands that, Java doesn't */ +{LBRACKET} / "^" {RBRACKET} { if (!allowNestedCharacterClasses) { + yypushstate(CLASS1PY); + } + else { + yypushstate(CLASS2); + } + return RegExpTT.CLASS_BEGIN; + } + +{LBRACKET} { yypushstate(CLASS2); + return RegExpTT.CLASS_BEGIN; } /* []abc] is legal. The first ] is treated as literal character */ { @@ -184,14 +232,20 @@ HEX_CHAR=[0-9a-fA-F] . { assert false : yytext(); } } + { + "^" { yybegin(CLASS1); return RegExpTT.CARET; } + . { assert false : yytext(); } +} + { {RBRACKET} { yypopstate(); return RegExpTT.CLASS_END; } - "&&" { return RegExpTT.ANDAND; } + "&&" { return allowNestedCharacterClasses ? RegExpTT.ANDAND : RegExpTT.CHARACTER; } [\n\b\t\r\f] { return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.ESC_CHARACTER; } {ANY} { return RegExpTT.CHARACTER; } } + { {LPAREN} { return RegExpTT.GROUP_BEGIN; } {RPAREN} { return RegExpTT.GROUP_END; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java index 363e7ef64adb..75830bc64d23 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java @@ -15,9 +15,8 @@ */ package com.intellij.debugger.ui.tree.render; -import com.intellij.ui.classFilter.ClassFilter; -import com.intellij.debugger.DebuggerContext; import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.DebuggerContext; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; @@ -29,6 +28,7 @@ import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.PsiExpression; +import com.intellij.ui.classFilter.ClassFilter; import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants; import com.sun.jdi.*; import org.jdom.Element; @@ -73,7 +73,7 @@ public class ToStringRenderer extends NodeRendererImpl { final Value value = valueDescriptor.getValue(); BatchEvaluator.getBatchEvaluator(evaluationContext.getDebugProcess()).invoke(new ToStringCommand(evaluationContext, value) { public void evaluationResult(String message) { - valueDescriptor.setValueLabel(message != null ? "\"" + message + "\"" : ""); + valueDescriptor.setValueLabel(message != null ? "\"" + DebuggerUtilsEx.truncateString(message) + "\"" : ""); labelListener.labelChanged(); } diff --git a/java/execution/impl/src/com/intellij/execution/junit/RefactoringListeners.java b/java/execution/impl/src/com/intellij/execution/junit/RefactoringListeners.java index 7e88f7ea46ea..fd2518cb3a5f 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/RefactoringListeners.java +++ b/java/execution/impl/src/com/intellij/execution/junit/RefactoringListeners.java @@ -22,6 +22,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.listeners.RefactoringElementAdapter; import com.intellij.refactoring.listeners.RefactoringElementListener; import org.jetbrains.annotations.NotNull; @@ -85,7 +86,7 @@ public class RefactoringListeners { } } - private static abstract class RenameElement implements RefactoringElementListener { + private static abstract class RenameElement extends RefactoringElementAdapter { private final Accessor myAccessor; private final String myPath; @@ -94,22 +95,15 @@ public class RefactoringListeners { myPath = path; } - public void elementMoved(@NotNull final PsiElement newElement) { - setName((T)newElement); - } - - public void elementRenamed(@NotNull final PsiElement newElement) { - setName((T)newElement); - } - - private void setName(@NotNull T newElement) { - String qualifiedName = getQualifiedName(newElement); + public void elementRenamedOrMoved(@NotNull final PsiElement newElement) { + T newElement1 = (T)newElement; + String qualifiedName = getQualifiedName(newElement1); if (myPath.length() > 0) { qualifiedName = qualifiedName + "." + myPath; - newElement = findNewElement(newElement, qualifiedName); + newElement1 = findNewElement(newElement1, qualifiedName); } - if (newElement != null) { - myAccessor.setPsiElement(newElement); + if (newElement1 != null) { + myAccessor.setPsiElement(newElement1); } else { myAccessor.setName(qualifiedName); diff --git a/java/execution/impl/src/com/intellij/execution/ui/ConfigurationArgumentsHelpArea.java b/java/execution/impl/src/com/intellij/execution/ui/ConfigurationArgumentsHelpArea.java index dbec76e5438a..aa7e95aa644e 100644 --- a/java/execution/impl/src/com/intellij/execution/ui/ConfigurationArgumentsHelpArea.java +++ b/java/execution/impl/src/com/intellij/execution/ui/ConfigurationArgumentsHelpArea.java @@ -18,13 +18,10 @@ package com.intellij.execution.ui; import com.intellij.execution.ExecutionBundle; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.ide.CopyPasteManager; -import com.intellij.openapi.project.Project; import com.intellij.ui.PopupHandler; -import com.intellij.util.ui.EmptyClipboardOwner; import javax.swing.*; import java.awt.*; -import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; public class ConfigurationArgumentsHelpArea extends JPanel { @@ -68,17 +65,8 @@ public class ConfigurationArgumentsHelpArea extends JPanel { } public void actionPerformed(final AnActionEvent e) { - try { - final StringSelection contents = new StringSelection(myHelpArea.getText().trim()); - final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); - if (project == null) { - final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(contents, EmptyClipboardOwner.INSTANCE); - } else { - CopyPasteManager.getInstance().setContents(contents); - } - } catch(Exception ex) { - } + final StringSelection contents = new StringSelection(myHelpArea.getText().trim()); + CopyPasteManager.getInstance().setContents(contents); } } diff --git a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java b/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java index 8193216423be..b6f2063a7043 100644 --- a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java +++ b/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java @@ -19,6 +19,7 @@ package com.intellij.ide.palette.impl; import com.intellij.ide.IdeBundle; import com.intellij.ide.palette.PaletteDragEventListener; import com.intellij.ide.palette.PaletteItem; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.FileEditorManagerEvent; @@ -60,20 +61,22 @@ public class PaletteManager implements ProjectComponent { } public void projectOpened() { - StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() { - public void run() { - myPaletteWindow = new PaletteWindow(myProject); - myPaletteToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(IdeBundle.message("toolwindow.palette"), - myPaletteWindow, - ToolWindowAnchor.RIGHT, - myProject, - true, false); - myPaletteToolWindow.setIcon(IconLoader.getIcon("/general/toolWindowPalette.png")); - myPaletteToolWindow.setAvailable(false, null); - final MyFileEditorManagerListener myListener = new MyFileEditorManagerListener(); - myFileEditorManager.addFileEditorManagerListener(myListener, myProject); - } - }); + if (!ApplicationManager.getApplication().isHeadlessEnvironment()) { + StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() { + public void run() { + myPaletteWindow = new PaletteWindow(myProject); + myPaletteToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(IdeBundle.message("toolwindow.palette"), + myPaletteWindow, + ToolWindowAnchor.RIGHT, + myProject, + true); + myPaletteToolWindow.setIcon(IconLoader.getIcon("/general/toolWindowPalette.png")); + myPaletteToolWindow.setAvailable(false, null); + final MyFileEditorManagerListener myListener = new MyFileEditorManagerListener(); + myFileEditorManager.addFileEditorManagerListener(myListener, myProject); + } + }); + } } public void projectClosed() { diff --git a/java/java-impl/java-impl.iml b/java/java-impl/java-impl.iml index c52f97bf075d..f5bd5cce2b5f 100644 --- a/java/java-impl/java-impl.iml +++ b/java/java-impl/java-impl.iml @@ -4,6 +4,7 @@ + diff --git a/java/java-impl/src/com/intellij/codeInsight/ExceptionUtil.java b/java/java-impl/src/com/intellij/codeInsight/ExceptionUtil.java index c7f3c32476d5..64fe99852282 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExceptionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExceptionUtil.java @@ -206,10 +206,10 @@ public class ExceptionUtil { PsiClassType exception = getUnhandledException(statement, topElement); unhandledExceptions = exception == null ? Collections.emptyList() : Collections.singletonList(exception); } - else if (element instanceof PsiCodeBlock - && element.getParent() instanceof PsiMethod - && ((PsiMethod)element.getParent()).isConstructor() - && !firstStatementIsConstructorCall((PsiCodeBlock)element)) { + else if (element instanceof PsiCodeBlock && + element.getParent() instanceof PsiMethod && + ((PsiMethod)element.getParent()).isConstructor() && + !firstStatementIsConstructorCall((PsiCodeBlock)element)) { // there is implicit parent constructor call final PsiMethod constructor = (PsiMethod)element.getParent(); final PsiClass aClass = constructor.getContainingClass(); @@ -246,6 +246,16 @@ public class ExceptionUtil { unhandledExceptions = unhandled; } + if (element instanceof PsiResource) { + final List unhandled = getUnhandledCloserExceptions((PsiResource)element, topElement); + if (unhandledExceptions == null) { + unhandledExceptions = unhandled; + } + else { + unhandledExceptions.addAll(unhandled); + } + } + if (unhandledExceptions != null) { if (foundExceptions == null) { foundExceptions = new THashSet(); @@ -309,19 +319,36 @@ public class ExceptionUtil { } @NotNull - public static List getUnhandledExceptions(PsiCallExpression methodCall, PsiElement topElement) { + public static List getUnhandledExceptions(final PsiCallExpression methodCall, final PsiElement topElement) { final JavaResolveResult result = methodCall.resolveMethodGenerics(); - PsiMethod method = (PsiMethod)result.getElement(); - return getUnhandledExceptions(method, methodCall, topElement, - ApplicationManager.getApplication().runReadAction(new Computable() { - public PsiSubstitutor compute() { - return result.getSubstitutor(); - } - })); + final PsiMethod method = (PsiMethod)result.getElement(); + final PsiSubstitutor substitutor = ApplicationManager.getApplication().runReadAction(new Computable() { + public PsiSubstitutor compute() { + return result.getSubstitutor(); + } + }); + return getUnhandledExceptions(method, methodCall, topElement, substitutor); + } + + @NotNull + public static List getUnhandledCloserExceptions(final PsiResource resource, final PsiElement topElement) { + final PsiType resourceType = resource.getType(); + if (resourceType instanceof PsiClassType) { + final PsiClass resourceClass = ((PsiClassType)resourceType).resolve(); + if (resourceClass != null) { + final PsiMethod[] closers = resourceClass.findMethodsByName("close", false); + for (final PsiMethod method : closers) { + if (method.getParameterList().getParametersCount() == 0) { + return getUnhandledExceptions(method, resource, topElement, PsiSubstitutor.EMPTY); + } + } + } + } + return Collections.emptyList(); } @Nullable - public static PsiClassType getUnhandledException(PsiThrowStatement throwStatement, PsiElement topElement){ + public static PsiClassType getUnhandledException(PsiThrowStatement throwStatement, PsiElement topElement) { final PsiExpression exception = throwStatement.getException(); if (exception != null) { final PsiType type = exception.getType(); @@ -335,7 +362,6 @@ public class ExceptionUtil { return null; } - @NotNull private static List getUnhandledExceptions(PsiMethod method, PsiElement element, diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index beaa799fa0fb..3f818584c3d4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -953,7 +953,7 @@ public class ExpectedTypesProvider { if (index >= params.length) { return TailType.NONE; } - if (index == params.length - 1) { + if (index == params.length - 1 || index == params.length - 2 && params[index + 1].isVarArgs()) { //myTailType = CompletionUtil.NONE_TAIL; final PsiElement call = argument.getParent().getParent(); if (call instanceof JspMethodCall) return TailType.NONE; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java index 92b9a74a0d1d..15028e8e538c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java @@ -31,7 +31,6 @@ import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,16 +38,15 @@ import java.util.Map; import static com.intellij.patterns.PsiJavaPatterns.psiClass; import static com.intellij.patterns.PsiJavaPatterns.psiElement; -import static com.intellij.patterns.StandardPatterns.not; /** * @author peter */ -public class BasicExpressionCompletionContributor extends ExpressionSmartCompletionContributor{ +public class BasicExpressionCompletionContributor { public static final ElementPattern AFTER_DOT = psiElement().afterLeaf("."); - private static void addKeyword(final CompletionResultSet result, final PsiElement element, final String s) { - result.addElement(createKeywordLookupItem(element, s)); + private static void addKeyword(final Consumer result, final PsiElement element, final String s) { + result.consume(createKeywordLookupItem(element, s)); } public static LookupElement createKeywordLookupItem(final PsiElement element, final String s) { @@ -61,31 +59,29 @@ public class BasicExpressionCompletionContributor extends ExpressionSmartComplet } } + public static void fillCompletionVariants(JavaSmartCompletionParameters parameters, + final Consumer result, + PrefixMatcher matcher) { + final PsiElement element = parameters.getPosition(); + if (PsiJavaPatterns.psiElement().afterLeaf( + PsiJavaPatterns.psiElement().withText(".").afterLeaf( + PsiJavaPatterns.psiElement().withParent( + PsiJavaPatterns.psiElement().referencing(psiClass())))).accepts(element)) { + addKeyword(result, element, PsiKeyword.CLASS); + addKeyword(result, element, PsiKeyword.THIS); - public BasicExpressionCompletionContributor() { - extend(PsiJavaPatterns.psiElement().afterLeaf( - PsiJavaPatterns.psiElement().withText(".").afterLeaf( - PsiJavaPatterns.psiElement().withParent( - PsiJavaPatterns.psiElement().referencing(psiClass())))), new CompletionProvider() { - public void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { - final PsiElement element = parameters.getPosition(); - addKeyword(result, element, PsiKeyword.CLASS); - addKeyword(result, element, PsiKeyword.THIS); - } + } - }); + if (!AFTER_DOT.accepts(element)) { + CollectionsUtilityMethodsProvider.addCompletions(parameters, result); + ClassLiteralGetter.addCompletions(parameters, result, matcher); - extend(not(AFTER_DOT), new CollectionsUtilityMethodsProvider()); - extend(not(AFTER_DOT), new ClassLiteralGetter()); - - extend(not(AFTER_DOT), new CompletionProvider() { - protected void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { - final PsiElement position = parameters.getPosition(); + final PsiElement position = parameters.getPosition(); final PsiType expectedType = parameters.getExpectedType(); for (final TemplateImpl template : TemplateSettings.getInstance().getTemplates()) { if (!template.isDeactivated() && template.getTemplateContext().isEnabled(new SmartCompletionContextType())) { - result.addElement(new SmartCompletionTemplateItem(template, position)); + result.consume(new SmartCompletionTemplateItem(template, position)); } } @@ -100,17 +96,12 @@ public class BasicExpressionCompletionContributor extends ExpressionSmartComplet } for (final PsiExpression expression : ThisGetter.getThisExpressionVariants(position)) { - result.addElement(new ExpressionLookupItem(expression)); + result.consume(new ExpressionLookupItem(expression)); } } - processDataflowExpressionTypes(position, expectedType, result.getPrefixMatcher(), new Consumer() { - public void consume(LookupElement decorator) { - result.addElement(decorator); - } - }); - } - }); + processDataflowExpressionTypes(position, expectedType, matcher, result); + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java index e39df303d589..a9f93fdde07b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java @@ -15,19 +15,21 @@ */ package com.intellij.codeInsight.completion; -import com.intellij.codeInsight.lookup.LookupItem; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.NonNls; -import com.intellij.util.ProcessingContext; -import com.intellij.psi.*; -import static com.intellij.psi.CommonClassNames.*; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.psi.*; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.psi.CommonClassNames.*; /** * @author peter */ -class CollectionsUtilityMethodsProvider extends CompletionProvider { - public void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { +class CollectionsUtilityMethodsProvider { + public static void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, + @NotNull final Consumer result) { final PsiElement element = parameters.getPosition(); final PsiElement parent = element.getParent(); @@ -63,7 +65,7 @@ class CollectionsUtilityMethodsProvider extends CompletionProvider result, final PsiType expectedType, final PsiType defaultType, final String baseClassName, @NonNls final String method, @NotNull final PsiClass collectionsClass) { if (isClassType(expectedType, baseClassName) || isClassType(expectedType, JAVA_UTIL_COLLECTION)) { @@ -73,7 +75,7 @@ class CollectionsUtilityMethodsProvider extends CompletionProvider result, PsiType expectedType, String methodName, PsiClass containingClass) { final PsiMethod[] methods = containingClass.findMethodsByName(methodName, false); if (methods.length == 0) { return; @@ -83,7 +85,7 @@ class CollectionsUtilityMethodsProvider extends CompletionProvider { - - private final List, CompletionProvider>> myList = - new ArrayList, CompletionProvider>>(); - - public final void extend(final ElementPattern place, CompletionProvider provider) { - myList.add(new Pair, CompletionProvider>(place, provider)); - } - - public void fillCompletionVariants(final JavaSmartCompletionParameters parameters, CompletionResultSet result) { - for (final Pair, CompletionProvider> pair : myList) { - final ProcessingContext context = new ProcessingContext(); - if (pair.first.accepts(parameters.getPosition(), context)) { - pair.second.addCompletionVariants(parameters, context, result); - } - } - } - -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java index 1d3cf746af7e..cc3d3fd2178f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java @@ -56,7 +56,7 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { CompletionService.getCompletionService().setAdvertisementText(CompletionBundle.message("completion.class.name.hint.2", getActionShortcut(IdeActions.ACTION_CLASS_NAME_COMPLETION))); } - final CompletionResultSet result = JavaCompletionContributor.addJavaSorting(parameters, _result); + final CompletionResultSet result = JavaCompletionSorting.addJavaSorting(parameters, _result); final PsiElement insertedElement = parameters.getPosition(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 5c834c965a1b..34c72286b8e6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -15,7 +15,6 @@ */ package com.intellij.codeInsight.completion; -import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFix; import com.intellij.codeInsight.hint.ShowParameterInfoHandler; @@ -182,7 +181,7 @@ public class JavaCompletionContributor extends CompletionContributor { } - final CompletionResultSet result = addJavaSorting(parameters, _result); + final CompletionResultSet result = JavaCompletionSorting.addJavaSorting(parameters, _result); if (ANNOTATION_ATTRIBUTE_NAME.accepts(position)) { completeAnnotationAttributeName(result, position, parameters); @@ -207,18 +206,6 @@ public class JavaCompletionContributor extends CompletionContributor { result.stopHere(); } - public static CompletionResultSet addJavaSorting(CompletionParameters parameters, CompletionResultSet result) { - final boolean afterNew = JavaSmartCompletionContributor.AFTER_NEW.accepts(parameters.getPosition()); - final ExpectedTypeInfo[] expectedTypes = afterNew ? JavaSmartCompletionContributor.getExpectedTypes(parameters) : ExpectedTypeInfo.EMPTY_ARRAY; - return result.withRelevanceSorter(CompletionSorter.defaultSorter(parameters).weighBefore("liftShorter", new LookupElementWeigher("expectedAfterNew") { - @NotNull - @Override - public Comparable weigh(@NotNull LookupElement element) { - return -((Enum)PreferExpectedTypeWeigher.weigh(element, expectedTypes)).ordinal(); - } - })); - } - public static void addAllClasses(CompletionParameters parameters, final CompletionResultSet result, PsiElement position, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java index faf84cdf482c..16b6c5c2064a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java @@ -39,6 +39,7 @@ import com.intellij.psi.jsp.JspElementType; import com.intellij.psi.scope.ElementClassFilter; import com.intellij.psi.templateLanguages.OuterLanguageElement; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.Consumer; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NonNls; @@ -503,8 +504,9 @@ public class JavaCompletionData extends JavaAwareCompletionData{ new ParentElementFilter(new ClassFilter(PsiSwitchLabelStatement.class)), new LeftNeighbour(new OrFilter( new ParentElementFilter(new ClassFilter(PsiSwitchStatement.class), 2), - new AndFilter(new TextFilter(";", "}", ":"),new ParentElementFilter(new ClassFilter(PsiSwitchStatement.class), 3) - )))))); + new AndFilter(new TextFilter(";", ":"),new ParentElementFilter(new ClassFilter(PsiSwitchStatement.class), 3)), + new AndFilter(new TextFilter("}"), new ParentElementFilter(new ClassFilter(PsiSwitchStatement.class), 4)) + ))))); variant.includeScopeClass(PsiElement.class, false); variant.addCompletion(PsiKeyword.CASE, TailType.SPACE); variant.addCompletion(PsiKeyword.DEFAULT, TailType.CASE_COLON); @@ -549,12 +551,19 @@ public class JavaCompletionData extends JavaAwareCompletionData{ } @Override - public void fillCompletions(CompletionParameters parameters, CompletionResultSet result) { + public void fillCompletions(CompletionParameters parameters, final CompletionResultSet result) { final PsiElement position = parameters.getPosition(); if (PsiTreeUtil.getParentOfType(position, PsiComment.class, false) != null) { return; } + final PsiExpressionStatement expressionStatement = PsiTreeUtil.getParentOfType(position, PsiExpressionStatement.class); + if (expressionStatement != null && expressionStatement.getTextRange().getStartOffset() == position.getTextRange().getStartOffset()) { + if (!psiElement().withSuperParent(2, PsiSwitchStatement.class).accepts(expressionStatement)) { + result.addElement(createKeyword(position, PsiKeyword.FINAL)); + } + } + if (SUPER_OR_THIS_PATTERN.accepts(position)) { if (AFTER_DOT.accepts(position) && !isInsideQualifierClass(position)) return; @@ -605,7 +614,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{ if (!PsiKeyword.VOID.equals(primitiveType)) { result.addElement(TailTypeDecorator.withTail(createKeyword(position, primitiveType), TailType.SPACE)); } - result.addElement(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.FINAL), TailType.SPACE)); + //result.addElement(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.FINAL), TailType.SPACE)); } } @@ -630,7 +639,12 @@ public class JavaCompletionData extends JavaAwareCompletionData{ !(position.getParent() instanceof PsiLiteralExpression) && !(position.getParent().getParent() instanceof PsiSwitchLabelStatement)) { for (final ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { - MembersGetter.addMembers(position, info.getDefaultType(), result); + MembersGetter.addMembers(position, info.getDefaultType(), new Consumer() { + @Override + public void consume(LookupElement element) { + result.addElement(element); + } + }); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java new file mode 100644 index 000000000000..77ce85355add --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -0,0 +1,592 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.ExpectedTypeInfo; +import com.intellij.codeInsight.ExpectedTypeInfoImpl; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementWeigher; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Pair; +import com.intellij.patterns.PsiJavaPatterns; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.NameUtil; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.filters.ElementFilter; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; +import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author peter + */ +public class JavaCompletionSorting { + private JavaCompletionSorting() { + } + + public static CompletionResultSet addJavaSorting(final CompletionParameters parameters, CompletionResultSet result) { + final PsiElement position = parameters.getPosition(); + final ExpectedTypeInfo[] expectedTypes = PsiJavaPatterns.psiElement().beforeLeaf(PsiJavaPatterns.psiElement().withText(".")).accepts(position) ? ExpectedTypeInfo.EMPTY_ARRAY : JavaSmartCompletionContributor.getExpectedTypes(parameters); + final CompletionType type = parameters.getCompletionType(); + final boolean smart = type == CompletionType.SMART; + final boolean afterNew = JavaSmartCompletionContributor.AFTER_NEW.accepts(position); + + List afterNegativeStats = new ArrayList(); + ContainerUtil.addIfNotNull(afterNegativeStats, smart ? new PreferDefaultTypeWeigher(expectedTypes, parameters) : preferStatics(position)); + afterNegativeStats.add(new PreferLocalVariablesLiteralsAndAnnoMethodsWeigher(type)); + ContainerUtil.addIfNotNull(afterNegativeStats, recursion(parameters, expectedTypes)); + if (!smart && !afterNew) { + afterNegativeStats.add(new PreferExpected(false, expectedTypes)); + } + afterNegativeStats.add(new PreferSimilarlyEnding(expectedTypes)); + + List afterProximity = new ArrayList(); + afterProximity.add(new PreferContainingSameWords(expectedTypes)); + if (smart) { + afterProximity.add(new PreferFieldsAndGetters()); + } + afterProximity.add(new PreferShorter(expectedTypes)); + + CompletionSorter sorter = CompletionSorter.defaultSorter(parameters); + if (!smart && afterNew) { + sorter = sorter.weighBefore("liftShorter", new PreferExpected(true, expectedTypes)); + } + sorter = sorter.weighAfter("negativeStats", afterNegativeStats.toArray(new LookupElementWeigher[afterNegativeStats.size()])); + sorter = sorter.weighAfter("prefix", new PreferNonGeneric(), new PreferAccessible(position), new PreferSimple(), new PreferEnumConstants(parameters)); + sorter = sorter.weighAfter("proximity", afterProximity.toArray(new LookupElementWeigher[afterProximity.size()])); + return result.withRelevanceSorter(sorter); + } + + @Nullable + private static LookupElementWeigher recursion(CompletionParameters parameters, final ExpectedTypeInfo[] expectedInfos) { + + final PsiElement position = parameters.getPosition(); + final PsiMethod positionMethod = PsiTreeUtil.getParentOfType(position, PsiMethod.class, false); + final ElementFilter filter = JavaCompletionUtil.recursionFilter(position); + final PsiMethodCallExpression expression = PsiTreeUtil.getParentOfType(position, PsiMethodCallExpression.class, true, PsiClass.class); + final PsiReferenceExpression reference = expression != null ? expression.getMethodExpression() : PsiTreeUtil.getParentOfType(position, PsiReferenceExpression.class); + if (reference == null) return null; + + return new RecursionWeigher(filter, position, reference, expression, positionMethod, expectedInfos); + } + + @Nullable + private static LookupElementWeigher preferStatics(PsiElement position) { + if (PsiTreeUtil.getParentOfType(position, PsiDocComment.class) != null) { + return null; + } + if (position.getParent() instanceof PsiReferenceExpression) { + final PsiReferenceExpression refExpr = (PsiReferenceExpression)position.getParent(); + final PsiElement qualifier = refExpr.getQualifier(); + if (qualifier == null) { + return null; + } + if (!(qualifier instanceof PsiJavaCodeReferenceElement) || !(((PsiJavaCodeReferenceElement)qualifier).resolve() instanceof PsiClass)) { + return null; + } + } + + return new LookupElementWeigher("statics") { + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + final Object o = element.getObject(); + if (!(o instanceof PsiMember)) return 0; + + if (((PsiMember)o).hasModifierProperty(PsiModifier.STATIC)) { + if (o instanceof PsiMethod) return -5; + if (o instanceof PsiField) return -4; + } + + if (o instanceof PsiClass) return -3; + + //instance method or field + return -5; + } + }; + } + + private static ExpectedTypeMatching getExpectedTypeMatching(LookupElement item, ExpectedTypeInfo[] expectedInfos) { + PsiType itemType = JavaCompletionUtil.getLookupElementType(item); + if (itemType == null) return ExpectedTypeMatching.normal; + + for (final ExpectedTypeInfo expectedInfo : expectedInfos) { + final PsiType defaultType = expectedInfo.getDefaultType(); + final PsiType expectedType = expectedInfo.getType(); + if (!expectedType.isValid()) { + return ExpectedTypeMatching.normal; + } + + if (defaultType != expectedType && defaultType.isAssignableFrom(itemType)) { + return ExpectedTypeMatching.ofDefaultType; + } + if (expectedType.isAssignableFrom(itemType)) { + return ExpectedTypeMatching.expected; + } + } + + return ExpectedTypeMatching.normal; + } + + @Nullable + private static String getLookupObjectName(Object o) { + if (o instanceof PsiVariable) { + final PsiVariable variable = (PsiVariable)o; + JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(variable.getProject()); + VariableKind variableKind = codeStyleManager.getVariableKind(variable); + return codeStyleManager.variableNameToPropertyName(variable.getName(), variableKind); + } + if (o instanceof PsiMethod) { + return ((PsiMethod)o).getName(); + } + return null; + } + + private static int getNameEndMatchingDegree(final String name, ExpectedTypeInfo[] expectedInfos, String prefix) { + int res = 0; + if (name != null && expectedInfos != null) { + if (prefix.equals(name)) { + res = Integer.MAX_VALUE; + } else { + final List words = NameUtil.nameToWordsLowerCase(name); + final List wordsNoDigits = NameUtil.nameToWordsLowerCase(truncDigits(name)); + int max1 = calcMatch(words, 0, expectedInfos); + max1 = calcMatch(wordsNoDigits, max1, expectedInfos); + res = max1; + } + } + + return res; + } + + private static String truncDigits(String name){ + int count = name.length() - 1; + while (count >= 0) { + char c = name.charAt(count); + if (!Character.isDigit(c)) break; + count--; + } + return name.substring(0, count + 1); + } + + private static int calcMatch(final List words, int max, ExpectedTypeInfo[] myExpectedInfos) { + for (ExpectedTypeInfo myExpectedInfo : myExpectedInfos) { + String expectedName = ((ExpectedTypeInfoImpl)myExpectedInfo).expectedName; + if (expectedName == null) continue; + max = calcMatch(expectedName, words, max); + max = calcMatch(truncDigits(expectedName), words, max); + } + return max; + } + + private static int calcMatch(final String expectedName, final List words, int max) { + if (expectedName == null) return max; + + String[] expectedWords = NameUtil.nameToWords(expectedName); + int limit = Math.min(words.size(), expectedWords.length); + for (int i = 0; i < limit; i++) { + String word = words.get(words.size() - i - 1); + String expectedWord = expectedWords[expectedWords.length - i - 1]; + if (word.equalsIgnoreCase(expectedWord)) { + max = Math.max(max, i + 1); + } + else { + break; + } + } + return max; + } + + private static class PreferDefaultTypeWeigher extends LookupElementWeigher { + private final PsiTypeParameter myTypeParameter; + private final ExpectedTypeInfo[] myExpectedTypes; + private final CompletionParameters myParameters; + private final CompletionLocation myLocation; + + public PreferDefaultTypeWeigher(ExpectedTypeInfo[] expectedTypes, CompletionParameters parameters) { + super("defaultType"); + myExpectedTypes = expectedTypes; + myParameters = parameters; + + final Pair pair = JavaSmartCompletionContributor.getTypeParameterInfo(parameters.getPosition()); + myTypeParameter = pair == null ? null : pair.first.getTypeParameters()[pair.second.intValue()]; + myLocation = new CompletionLocation(myParameters); + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement item) { + final Object object = item.getObject(); + + if (object instanceof PsiClass) { + if (myTypeParameter != null && object.equals(PsiUtil.resolveClassInType(TypeConversionUtil.typeParameterErasure(myTypeParameter)))) { + return MyResult.exactlyExpected; + } + } + + if (myExpectedTypes == null) return MyResult.normal; + + PsiType itemType = JavaCompletionUtil.getLookupElementType(item); + if (itemType == null || !itemType.isValid()) return MyResult.normal; + + if (object instanceof PsiClass) { + for (final ExpectedTypeInfo info : myExpectedTypes) { + if (TypeConversionUtil.erasure(info.getType().getDeepComponentType()).equals(TypeConversionUtil.erasure(itemType))) { + return AbstractExpectedTypeSkipper.skips(item, myLocation) ? MyResult.expectedNoSelect : MyResult.exactlyExpected; + } + } + } + + for (final ExpectedTypeInfo expectedInfo : myExpectedTypes) { + final PsiType defaultType = expectedInfo.getDefaultType(); + final PsiType expectedType = expectedInfo.getType(); + if (!expectedType.isValid()) { + return MyResult.normal; + } + + if (defaultType != expectedType) { + if (defaultType.equals(itemType)) { + return MyResult.exactlyDefault; + } + + if (defaultType.isAssignableFrom(itemType)) { + return MyResult.ofDefaultType; + } + } + if (PsiType.VOID.equals(itemType) && PsiType.VOID.equals(expectedType)) { + return MyResult.exactlyExpected; + } + } + + return MyResult.normal; + } + + private enum MyResult { + expectedNoSelect, + exactlyDefault, + ofDefaultType, + exactlyExpected, + normal, + } + + } + + private static class RecursionWeigher extends LookupElementWeigher { + private final ElementFilter myFilter; + private final PsiElement myPosition; + private final PsiReferenceExpression myReference; + private final PsiMethodCallExpression myExpression; + private final PsiMethod myPositionMethod; + private final ExpectedTypeInfo[] myExpectedInfos; + private final PsiExpression myQualifier; + private final boolean myDelegate; + + public RecursionWeigher(ElementFilter filter, + PsiElement position, + @NotNull PsiReferenceExpression reference, + PsiMethodCallExpression expression, + PsiMethod positionMethod, ExpectedTypeInfo[] expectedInfos) { + super("recursion"); + myFilter = filter; + myPosition = position; + myReference = reference; + myExpression = expression; + myPositionMethod = positionMethod; + myExpectedInfos = expectedInfos; + myQualifier = myReference.getQualifierExpression(); + myDelegate = myQualifier != null && !(myQualifier instanceof PsiThisExpression); + } + + private enum Result { + delegation, + normal, + passingObjectToItself, + recursive, + } + + @NotNull + @Override + public Result weigh(@NotNull LookupElement element) { + final Object object = element.getObject(); + if (!(object instanceof PsiMethod || object instanceof PsiVariable || object instanceof PsiExpression)) return Result.normal; + + if (myFilter != null && !myFilter.isAcceptable(object, myPosition)) { + return Result.recursive; + } + + if (isPassingObjectToItself(object)) { + return Result.passingObjectToItself; + } + + if (myExpression != null && myPositionMethod != null) { + if (myExpectedInfos != null) { + final PsiType itemType = JavaCompletionUtil.getLookupElementType(element); + if (itemType != null) { + for (final ExpectedTypeInfo expectedInfo : myExpectedInfos) { + if (myPositionMethod.equals(expectedInfo.getCalledMethod()) && expectedInfo.getType().isAssignableFrom(itemType)) { + return myDelegate ? Result.delegation : Result.recursive; + } + } + } + } + return Result.normal; + } + + if (object instanceof PsiMethod && myPositionMethod != null) { + final PsiMethod method = (PsiMethod)object; + if (PsiTreeUtil.isAncestor(myReference, myPosition, false) && + Comparing.equal(method.getName(), myPositionMethod.getName())) { + if (!myDelegate && findDeepestSuper(method).equals(findDeepestSuper(myPositionMethod))) { + return Result.recursive; + } + return Result.delegation; + } + } + + return Result.normal; + } + + private boolean isPassingObjectToItself(Object object) { + if (object instanceof PsiThisExpression) { + return !myDelegate || myQualifier instanceof PsiSuperExpression; + } + return myQualifier instanceof PsiReferenceExpression && + object.equals(((PsiReferenceExpression)myQualifier).advancedResolve(true).getElement()); + } + + @NotNull + private static PsiMethod findDeepestSuper(@NotNull final PsiMethod method) { + final PsiMethod first = DeepestSuperMethodsSearch.search(method).findFirst(); + return first == null ? method : first; + } + } + + private enum ExpectedTypeMatching { + ofDefaultType, + expected, + normal, + } + + private static class PreferAccessible extends LookupElementWeigher { + private final PsiElement myPosition; + + public PreferAccessible(PsiElement position) { + super("accessible"); + myPosition = position; + } + + private enum MyEnum { + NORMAL, + DEPRECATED, + INACCESSIBLE, + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + final Object object = element.getObject(); + if (object instanceof PsiDocCommentOwner) { + final PsiDocCommentOwner member = (PsiDocCommentOwner)object; + if (!member.isValid()) { + return MyEnum.NORMAL; + } + + if (!JavaPsiFacade.getInstance(member.getProject()).getResolveHelper().isAccessible(member, myPosition, null)) return MyEnum.INACCESSIBLE; + if (member.isDeprecated()) return MyEnum.DEPRECATED; + } + return MyEnum.NORMAL; + } + } + + private static class PreferNonGeneric extends LookupElementWeigher { + public PreferNonGeneric() { + super("nonGeneric"); + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + final Object object = element.getObject(); + if (object instanceof PsiMethod) { + PsiType type = ((PsiMethod)object).getReturnType(); + final JavaMethodCallElement callItem = element.as(JavaMethodCallElement.CLASS_CONDITION_KEY); + if (callItem != null) { + type = callItem.getSubstitutor().substitute(type); + } + + if (type instanceof PsiClassType && ((PsiClassType) type).resolve() instanceof PsiTypeParameter) return 1; + } + + return 0; + } + } + + private static class PreferSimple extends LookupElementWeigher { + public PreferSimple() { + super("simple"); + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + final PsiTypeLookupItem lookupItem = element.as(PsiTypeLookupItem.CLASS_CONDITION_KEY); + if (lookupItem != null) { + return lookupItem.getBracketsCount(); + } + if (element.as(CastingLookupElementDecorator.CLASS_CONDITION_KEY) != null) { + return 239; + } + return 0; + } + } + + private static class PreferEnumConstants extends LookupElementWeigher { + private final CompletionParameters myParameters; + + public PreferEnumConstants(CompletionParameters parameters) { + super("constants"); + myParameters = parameters; + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + if (element.getObject() instanceof PsiEnumConstant) return -2; + + if (!(myParameters.getOriginalFile() instanceof PsiJavaFile)) return -1; + + if (PsiKeyword.TRUE.equals(element.getLookupString()) || PsiKeyword.FALSE.equals(element.getLookupString())) { + boolean inReturn = PsiTreeUtil.getParentOfType(myParameters.getPosition(), PsiReturnStatement.class, false, PsiMember.class) != null; + return inReturn ? -2 : 0; + } + + return -1; + } + } + + private static class PreferExpected extends LookupElementWeigher { + private final boolean myAcceptClasses; + private final ExpectedTypeInfo[] myExpectedTypes; + + public PreferExpected(boolean acceptClasses, ExpectedTypeInfo[] expectedTypes) { + super("expectedType"); + myAcceptClasses = acceptClasses; + myExpectedTypes = expectedTypes; + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement item) { + return item.getObject() instanceof PsiClass && !myAcceptClasses + ? ExpectedTypeMatching.normal : getExpectedTypeMatching(item, myExpectedTypes); + } + } + + private static class PreferSimilarlyEnding extends LookupElementWeigher { + private final ExpectedTypeInfo[] myExpectedTypes; + + public PreferSimilarlyEnding(ExpectedTypeInfo[] expectedTypes) { + super("nameEnd"); + myExpectedTypes = expectedTypes; + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + final String name = getLookupObjectName(element.getObject()); + return -getNameEndMatchingDegree(name, myExpectedTypes, element.getPrefixMatcher().getPrefix()); + } + } + + private static class PreferContainingSameWords extends LookupElementWeigher { + private final ExpectedTypeInfo[] myExpectedTypes; + + public PreferContainingSameWords(ExpectedTypeInfo[] expectedTypes) { + super("sameWords"); + myExpectedTypes = expectedTypes; + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + final Object object = element.getObject(); + + final String name = getLookupObjectName(object); + if (name != null) { + int max = 0; + final List wordsNoDigits = NameUtil.nameToWordsLowerCase(truncDigits(name)); + for (ExpectedTypeInfo myExpectedInfo : myExpectedTypes) { + String expectedName = ((ExpectedTypeInfoImpl)myExpectedInfo).expectedName; + if (expectedName != null) { + final THashSet set = new THashSet(NameUtil.nameToWordsLowerCase(truncDigits(expectedName))); + set.retainAll(wordsNoDigits); + max = Math.max(max, set.size()); + } + } + return -max; + } + return 0; + } + } + + private static class PreferFieldsAndGetters extends LookupElementWeigher { + public PreferFieldsAndGetters() { + super("fieldsAndGetters"); + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + final Object object = element.getObject(); + if (object instanceof PsiField) return -2; + if (object instanceof PsiMethod && PropertyUtil.isSimplePropertyGetter((PsiMethod)object)) return -1; + return 0; + } + } + + private static class PreferShorter extends LookupElementWeigher { + private final ExpectedTypeInfo[] myExpectedTypes; + + public PreferShorter(ExpectedTypeInfo[] expectedTypes) { + super("shorter"); + myExpectedTypes = expectedTypes; + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement element) { + final Object object = element.getObject(); + final String name = getLookupObjectName(object); + + if (name != null && getNameEndMatchingDegree(name, myExpectedTypes, element.getPrefixMatcher().getPrefix()) != 0) { + return NameUtil.nameToWords(name).length - 1000; + } + return 0; + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 8969ae0704a5..a9eb9b56f2ae 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -105,23 +105,15 @@ public class JavaCompletionUtil { public static Set getExpectedTypes(final CompletionParameters parameters) { final PsiExpression expr = PsiTreeUtil.getContextOfType(parameters.getPosition(), PsiExpression.class, true); if (expr != null) { - final ExpectedTypeInfo[] expectedInfos = JavaSmartCompletionContributor.getExpectedTypes(parameters); - if(expectedInfos != null){ - final Set set = new THashSet(); - for (final ExpectedTypeInfo expectedInfo : expectedInfos) { - set.add(expectedInfo.getType()); - } - return set; + final Set set = new THashSet(); + for (final ExpectedTypeInfo expectedInfo : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { + set.add(expectedInfo.getType()); } + return set; } return null; } - static final NullableLazyKey POSITION_METHOD = NullableLazyKey.create("positionMethod", new NullableFunction() { - public PsiMethod fun(final CompletionLocation location) { - return PsiTreeUtil.getParentOfType(location.getCompletionParameters().getPosition(), PsiMethod.class, false); - } - }); public static final Key> ALL_METHODS_ATTRIBUTE = Key.create("allMethods"); public static PsiType getQualifierType(LookupItem item) { @@ -323,26 +315,12 @@ public class JavaCompletionUtil { final PsiReference reference = file.findReferenceAt(selectionEndOffset); if(reference != null) { - /* - if(reference instanceof PsiJavaCodeReferenceElement){ - offsetMap.addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, element.getParent().getTextRange().getEndOffset()); - } - else{ - } - */ offsetMap.addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, reference.getElement().getTextRange().getStartOffset() + reference.getRangeInElement().getEndOffset()); element = file.findElementAt(offsetMap.getOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET)); } else if (isWord(element)){ - /* - if(element instanceof PsiIdentifier && element.getParent() instanceof PsiJavaCodeReferenceElement){ - offsetMap.addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, element.getParent().getTextRange().getEndOffset()); - } - else{ - } - */ offsetMap.addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, element.getTextRange().getEndOffset()); element = file.findElementAt(offsetMap.getOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET)); @@ -432,75 +410,6 @@ public class JavaCompletionUtil { return null; } - public static int getNameEndMatchingDegree(final String name, ExpectedTypeInfo[] expectedInfos, String prefix) { - int res = 0; - if (name != null && expectedInfos != null) { - if (prefix.equals(name)) { - res = Integer.MAX_VALUE; - } else { - final List words = NameUtil.nameToWordsLowerCase(name); - final List wordsNoDigits = NameUtil.nameToWordsLowerCase(truncDigits(name)); - int max1 = calcMatch(words, 0, expectedInfos); - max1 = calcMatch(wordsNoDigits, max1, expectedInfos); - res = max1; - } - } - - return res; - } - - static String truncDigits(String name){ - int count = name.length() - 1; - while (count >= 0) { - char c = name.charAt(count); - if (!Character.isDigit(c)) break; - count--; - } - return name.substring(0, count + 1); - } - - private static int calcMatch(final List words, int max, ExpectedTypeInfo[] myExpectedInfos) { - for (ExpectedTypeInfo myExpectedInfo : myExpectedInfos) { - String expectedName = ((ExpectedTypeInfoImpl)myExpectedInfo).expectedName; - if (expectedName == null) continue; - max = calcMatch(expectedName, words, max); - max = calcMatch(truncDigits(expectedName), words, max); - } - return max; - } - - static int calcMatch(final String expectedName, final List words, int max) { - if (expectedName == null) return max; - - String[] expectedWords = NameUtil.nameToWords(expectedName); - int limit = Math.min(words.size(), expectedWords.length); - for (int i = 0; i < limit; i++) { - String word = words.get(words.size() - i - 1); - String expectedWord = expectedWords[expectedWords.length - i - 1]; - if (word.equalsIgnoreCase(expectedWord)) { - max = Math.max(max, i + 1); - } - else { - break; - } - } - return max; - } - - @Nullable - static String getLookupObjectName(Object o) { - if (o instanceof PsiVariable) { - final PsiVariable variable = (PsiVariable)o; - JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(variable.getProject()); - VariableKind variableKind = codeStyleManager.getVariableKind(variable); - return codeStyleManager.variableNameToPropertyName(variable.getName(), variableKind); - } - if (o instanceof PsiMethod) { - return ((PsiMethod)o).getName(); - } - return null; - } - @Nullable public static PsiType getLookupElementType(final LookupElement element) { TypedLookupItem typed = element.as(TypedLookupItem.CLASS_CONDITION_KEY); @@ -573,7 +482,7 @@ public class JavaCompletionUtil { return matcher.prefixMatches(s); } }; - final JavaCompletionProcessor processor = new JavaCompletionProcessor(element, elementFilter, checkAccess, nameCondition); + final JavaCompletionProcessor processor = new JavaCompletionProcessor(element, elementFilter, checkAccess, parameters.getInvocationCount() <= 1, nameCondition); javaReference.processVariants(processor); final Collection plainResults = processor.getResults(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java index e57b990ae312..aea4cc222e4c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java @@ -77,7 +77,7 @@ public class JavaDocCompletionContributor extends CompletionContributor { if (ref instanceof PsiJavaReference) { result.stopHere(); - final JavaCompletionProcessor processor = new JavaCompletionProcessor(position, TrueFilter.INSTANCE, false, null); + final JavaCompletionProcessor processor = new JavaCompletionProcessor(position, TrueFilter.INSTANCE, false, false, null); ((PsiJavaReference) ref).processVariants(processor); for (final CompletionElement _item : processor.getResults()) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java index baa48c694966..89a928ecb034 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java @@ -135,8 +135,11 @@ public class JavaInheritorsGetter extends CompletionProvider()", parameters.getOriginalFile()); final PsiVariable declaredVar = (PsiVariable)((PsiDeclarationStatement)statement).getDeclaredElements()[0]; - final PsiExpression initializer = declaredVar.getInitializer(); - psiType = initializer.getType(); + final PsiNewExpression initializer = (PsiNewExpression)declaredVar.getInitializer(); + final boolean hasDefaultConstructorOrNoGenericsOne = PsiDiamondType.hasDefaultConstructor(psiClass) || !PsiDiamondType.haveConstructorsGenericsParameters(psiClass); + if (hasDefaultConstructorOrNoGenericsOne && PsiDiamondType.resolveInferredTypes(initializer).getErrorMessage() == null) { + psiType = initializer.getType(); + } } } final LookupItem item = PsiTypeLookupItem.createLookupItem(psiType, parameters.getPosition()); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java index d91b3aba7e2b..e75b14747528 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java @@ -141,6 +141,12 @@ public class JavaMethodCallElement extends LookupItem implements Type return false; } } + if (leaf != null) { + final PsiElement parent = leaf.getParent(); + if (parent instanceof PsiReferenceExpression && ((PsiReferenceExpression)parent).getTypeParameters().length > 0) { + return false; + } + } return SmartCompletionDecorator.hasUnboundTypeParams(getObject()); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index 57b98d2a4cc6..1866660fc41d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -197,9 +197,9 @@ public class JavaSmartCompletionContributor extends CompletionContributor { final JavaSmartCompletionParameters parameters = new JavaSmartCompletionParameters(params, info); final PsiType type = info.getType(); - final CompletionService service = CompletionService.getCompletionService(); - new BasicExpressionCompletionContributor().fillCompletionVariants(parameters, service.createResultSet(parameters, new Consumer() { - public void consume(final LookupElement lookupElement) { + BasicExpressionCompletionContributor.fillCompletionVariants(parameters, new Consumer() { + @Override + public void consume(LookupElement lookupElement) { final TypedLookupItem typed = lookupElement.as(TypedLookupItem.CLASS_CONDITION_KEY); if (typed != null) { final PsiType psiType = typed.getType(); @@ -208,12 +208,12 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } } } - }, JavaSmartCompletionContributor.this)); - ReferenceExpressionCompletionContributor.fillCompletionVariants(parameters, service.createResultSet(parameters, new Consumer() { + }, result.getPrefixMatcher()); + ReferenceExpressionCompletionContributor.fillCompletionVariants(parameters, new Consumer() { public void consume(final LookupElement lookupElement) { result.addElement(decorate(lookupElement, _infos)); } - }, JavaSmartCompletionContributor.this)); + }); } } @@ -335,6 +335,11 @@ public class JavaSmartCompletionContributor extends CompletionContributor { extend(CompletionType.SMART, AFTER_NEW, new JavaInheritorsGetter(ConstructorInsertHandler.SMART_INSTANCE)); } + @Override + public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) { + super.fillCompletionVariants(parameters, JavaCompletionSorting.addJavaSorting(parameters, result)); + } + public static SmartCompletionDecorator decorate(LookupElement lookupElement, Collection infos) { if (lookupElement instanceof LookupItem) { final LookupItem lookupItem = (LookupItem)lookupElement; @@ -397,6 +402,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } + @NotNull public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters) { final PsiElement position = parameters.getPosition(); if (psiElement().withParent(psiElement(PsiReferenceExpression.class).withParent(PsiThrowStatement.class)).accepts(position)) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/NameEndMatchingDegreeWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/NameEndMatchingDegreeWeigher.java deleted file mode 100644 index f4b1bda9efdd..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/NameEndMatchingDegreeWeigher.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.lookup.LookupElement; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author peter -*/ -public class NameEndMatchingDegreeWeigher extends CompletionWeigher { - - public Integer weigh(@NotNull final LookupElement element, @NotNull final CompletionLocation location) { - if (location == null) { - return null; - } - final String name = JavaCompletionUtil.getLookupObjectName(element.getObject()); - return JavaCompletionUtil.getNameEndMatchingDegree(name, JavaCompletionUtil.EXPECTED_TYPES.getValue(location), - element.getPrefixMatcher().getPrefix()); - } - -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferAccessibleWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferAccessibleWeigher.java deleted file mode 100644 index 816f95b97f0e..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferAccessibleWeigher.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiDocCommentOwner; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author peter -*/ -public class PreferAccessibleWeigher extends CompletionWeigher { - - public MyEnum weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { - if (location == null) { - return null; - } - final Object object = item.getObject(); - if (object instanceof PsiDocCommentOwner) { - final PsiDocCommentOwner member = (PsiDocCommentOwner)object; - if (!member.isValid()) { - return MyEnum.NORMAL; - } - - if (!JavaPsiFacade.getInstance(member.getProject()).getResolveHelper().isAccessible(member, location.getCompletionParameters().getPosition(), null)) return MyEnum.INACCESSIBLE; - if (member.isDeprecated()) return MyEnum.DEPRECATED; - } - return MyEnum.NORMAL; - } - - private enum MyEnum { - INACCESSIBLE, - DEPRECATED, - NORMAL - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferDefaultTypeWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferDefaultTypeWeigher.java deleted file mode 100644 index 0b66e21022c2..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferDefaultTypeWeigher.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.ExpectedTypeInfo; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.openapi.util.NullableLazyKey; -import com.intellij.openapi.util.Pair; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiType; -import com.intellij.psi.PsiTypeParameter; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.NullableFunction; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author peter -*/ -public class PreferDefaultTypeWeigher extends CompletionWeigher { - private static final NullableLazyKey TYPE_PARAMETER = NullableLazyKey.create("expectedTypes", new NullableFunction() { - @Nullable - public PsiTypeParameter fun(final CompletionLocation location) { - final Pair pair = - JavaSmartCompletionContributor.getTypeParameterInfo(location.getCompletionParameters().getPosition()); - if (pair == null) return null; - return pair.first.getTypeParameters()[pair.second.intValue()]; - } - }); - - - private enum MyResult { - normal, - exactlyExpected, - ofDefaultType, - exactlyDefault, - expectedNoSelect - } - - public MyResult weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { - if (location == null) { - return null; - } - final Object object = item.getObject(); - if (location.getCompletionType() != CompletionType.SMART) return MyResult.normal; - - if (object instanceof PsiClass) { - final PsiTypeParameter parameter = TYPE_PARAMETER.getValue(location); - if (parameter != null && object.equals(PsiUtil.resolveClassInType(TypeConversionUtil.typeParameterErasure(parameter)))) { - return MyResult.exactlyExpected; - } - } - - ExpectedTypeInfo[] expectedInfos = JavaCompletionUtil.EXPECTED_TYPES.getValue(location); - if (expectedInfos == null) return MyResult.normal; - - PsiType itemType = JavaCompletionUtil.getLookupElementType(item); - if (itemType == null || !itemType.isValid()) return MyResult.normal; - - if (object instanceof PsiClass) { - for (final ExpectedTypeInfo info : expectedInfos) { - if (TypeConversionUtil.erasure(info.getType().getDeepComponentType()).equals(TypeConversionUtil.erasure(itemType))) { - return AbstractExpectedTypeSkipper.skips(item, location) ? MyResult.expectedNoSelect : MyResult.exactlyExpected; - } - } - } - - for (final ExpectedTypeInfo expectedInfo : expectedInfos) { - final PsiType defaultType = expectedInfo.getDefaultType(); - final PsiType expectedType = expectedInfo.getType(); - if (!expectedType.isValid()) { - return MyResult.normal; - } - - if (defaultType != expectedType) { - if (defaultType.equals(itemType)) { - return MyResult.exactlyDefault; - } - - if (defaultType.isAssignableFrom(itemType)) { - return MyResult.ofDefaultType; - } - } - if (PsiType.VOID.equals(itemType) && PsiType.VOID.equals(expectedType)) { - return MyResult.exactlyExpected; - } - } - - return MyResult.normal; - } -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferEnumConstantsWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferEnumConstantsWeigher.java deleted file mode 100644 index 325fdae2bf16..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferEnumConstantsWeigher.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author peter -*/ -public class PreferEnumConstantsWeigher extends CompletionWeigher { - - public Comparable weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { - if (location == null) { - return null; - } - if (item.getObject() instanceof PsiEnumConstant) return 2; - - final CompletionParameters parameters = location.getCompletionParameters(); - if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return 1; - - if (PsiKeyword.TRUE.equals(item.getLookupString()) || PsiKeyword.FALSE.equals(item.getLookupString())) { - boolean inReturn = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiReturnStatement.class, false, PsiMember.class) != null; - return inReturn ? 2 : 0; - } - - return 1; - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferExpectedTypeWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferExpectedTypeWeigher.java deleted file mode 100644 index 37b8ae55d171..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferExpectedTypeWeigher.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.ExpectedTypeInfo; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiType; -import org.jetbrains.annotations.NotNull; - -/** - * @author peter -*/ -public class PreferExpectedTypeWeigher extends CompletionWeigher { - - private enum MyResult { - normal, - expected, - ofDefaultType, - } - - public MyResult weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { - if (location.getCompletionType() != CompletionType.BASIC) return MyResult.normal; - if (item.getObject() instanceof PsiClass) { - if (!JavaSmartCompletionContributor.AFTER_NEW.accepts(location.getCompletionParameters().getPosition())) { - return MyResult.normal; - } - } - - ExpectedTypeInfo[] expectedInfos = JavaCompletionUtil.EXPECTED_TYPES.getValue(location); - if (expectedInfos == null) return MyResult.normal; - - return weigh(item, expectedInfos); - } - - public static MyResult weigh(LookupElement item, ExpectedTypeInfo[] expectedInfos) { - PsiType itemType = JavaCompletionUtil.getLookupElementType(item); - if (itemType == null) return MyResult.normal; - - for (final ExpectedTypeInfo expectedInfo : expectedInfos) { - final PsiType defaultType = expectedInfo.getDefaultType(); - final PsiType expectedType = expectedInfo.getType(); - if (!expectedType.isValid()) { - return MyResult.normal; - } - - if (defaultType != expectedType && defaultType.isAssignableFrom(itemType)) { - return MyResult.ofDefaultType; - } - if (expectedType.isAssignableFrom(itemType)) { - return MyResult.expected; - } - } - - return MyResult.normal; - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferFieldsAndGettersWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferFieldsAndGettersWeigher.java deleted file mode 100644 index c92faccbb46c..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferFieldsAndGettersWeigher.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.psi.PsiField; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.util.PropertyUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author peter -*/ -public class PreferFieldsAndGettersWeigher extends CompletionWeigher { - - public Comparable weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { - if (location == null) { - return null; - } - if (location.getCompletionType() != CompletionType.SMART) return 0; - - final Object object = item.getObject(); - if (object instanceof PsiField) return 2; - if (object instanceof PsiMethod && PropertyUtil.isSimplePropertyGetter((PsiMethod)object)) return 1; - return 0; - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java index c8a837d1177a..7529eb848e53 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java @@ -16,38 +16,47 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementWeigher; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; /** * @author peter */ -public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends CompletionWeigher { +public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends LookupElementWeigher { + private final CompletionType myCompletionType; - enum MyResult { - className, - classLiteral, - normal, - superMethodParameters, - localOrParameter, - annoMethod, + public PreferLocalVariablesLiteralsAndAnnoMethodsWeigher(CompletionType completionType) { + super("local"); + myCompletionType = completionType; } - public MyResult weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { + enum MyResult { + annoMethod, + localOrParameter, + superMethodParameters, + normal, + classLiteral, + className, + } + + @NotNull + @Override + public Comparable weigh(@NotNull LookupElement item) { final Object object = item.getObject(); if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) { return MyResult.localOrParameter; } - if (location.getCompletionType() == CompletionType.SMART) { + if (myCompletionType == CompletionType.SMART) { if (object instanceof String && item.getUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS) == Boolean.TRUE) { return MyResult.superMethodParameters; } return MyResult.normal; } - if (location.getCompletionType() == CompletionType.BASIC) { + if (myCompletionType == CompletionType.BASIC) { if (object instanceof PsiKeyword && PsiKeyword.CLASS.equals(item.getLookupString())) { return MyResult.classLiteral; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferNonGenericWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferNonGenericWeigher.java deleted file mode 100644 index a3f8154cca60..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferNonGenericWeigher.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.psi.PsiClassType; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiType; -import com.intellij.psi.PsiTypeParameter; -import org.jetbrains.annotations.NotNull; - -/** - * @author peter -*/ -public class PreferNonGenericWeigher extends CompletionWeigher { - - public Comparable weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { - final Object object = item.getObject(); - if (object instanceof PsiMethod) { - PsiType type = ((PsiMethod)object).getReturnType(); - final JavaMethodCallElement callItem = item.as(JavaMethodCallElement.CLASS_CONDITION_KEY); - if (callItem != null) { - type = callItem.getSubstitutor().substitute(type); - } - - if (type instanceof PsiClassType && ((PsiClassType) type).resolve() instanceof PsiTypeParameter) return -1; - } - - return 0; - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferShorterWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferShorterWeigher.java deleted file mode 100644 index 223559778dbd..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferShorterWeigher.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.ExpectedTypeInfo; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.psi.codeStyle.NameUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author peter -*/ -public class PreferShorterWeigher extends CompletionWeigher { - - public Comparable weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { - if (location == null) { - return null; - } - final Object object = item.getObject(); - final String name = JavaCompletionUtil.getLookupObjectName(object); - final ExpectedTypeInfo[] expectedInfos = JavaCompletionUtil.EXPECTED_TYPES.getValue(location); - - if (name != null && expectedInfos != null && JavaCompletionUtil.getNameEndMatchingDegree(name, expectedInfos, - item.getPrefixMatcher().getPrefix()) != 0) { - return 239 - NameUtil.nameToWords(name).length; - } - return 0; - - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferSimpleWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferSimpleWeigher.java deleted file mode 100644 index c7361df1f7af..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferSimpleWeigher.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.PsiTypeLookupItem; -import org.jetbrains.annotations.NotNull; - -/** - * @author peter -*/ -public class PreferSimpleWeigher extends CompletionWeigher { - - public Comparable weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { - final PsiTypeLookupItem lookupItem = item.as(PsiTypeLookupItem.CLASS_CONDITION_KEY); - if (lookupItem != null) { - return -lookupItem.getBracketsCount(); - } - if (item.as(CastingLookupElementDecorator.CLASS_CONDITION_KEY) != null) { - return -239; - } - return 0; - } -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java deleted file mode 100644 index 4eb4fc592ad4..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/RecursionWeigher.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.ExpectedTypeInfo; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.openapi.util.Comparing; -import com.intellij.psi.*; -import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; - -/** - * @author peter - */ -public class RecursionWeigher extends CompletionWeigher { - - private enum Result { - recursive, - passingObjectToItself, - normal, - delegation, - } - - public Result weigh(@NotNull final LookupElement element, @NotNull final CompletionLocation location) { - if (location.getCompletionType() != CompletionType.BASIC && location.getCompletionType() != CompletionType.SMART) return Result.normal; - - final Object object = element.getObject(); - if (!(object instanceof PsiMethod || object instanceof PsiVariable || object instanceof PsiExpression)) return Result.normal; - - final PsiMethod positionMethod = JavaCompletionUtil.POSITION_METHOD.getValue(location); - - final PsiElement position = location.getCompletionParameters().getPosition(); - final ElementFilter filter = JavaCompletionUtil.recursionFilter(position); - if (filter != null && !filter.isAcceptable(object, position)) { - return Result.recursive; - } - - final PsiMethodCallExpression expression = PsiTreeUtil.getParentOfType(position, PsiMethodCallExpression.class, true, PsiClass.class); - final PsiReferenceExpression reference = expression != null ? expression.getMethodExpression() : PsiTreeUtil.getParentOfType(position, PsiReferenceExpression.class); - if (reference == null) return Result.normal; - - final PsiExpression qualifier = reference.getQualifierExpression(); - boolean isDelegate = qualifier != null && !(qualifier instanceof PsiThisExpression); - - if (isPassingObjectToItself(object, qualifier, isDelegate)) { - return Result.passingObjectToItself; - } - - if (expression != null && positionMethod != null) { - final ExpectedTypeInfo[] expectedInfos = JavaCompletionUtil.EXPECTED_TYPES.getValue(location); - if (expectedInfos != null) { - final PsiType itemType = JavaCompletionUtil.getLookupElementType(element); - if (itemType != null) { - for (final ExpectedTypeInfo expectedInfo : expectedInfos) { - if (positionMethod.equals(expectedInfo.getCalledMethod()) && expectedInfo.getType().isAssignableFrom(itemType)) { - return isDelegate ? Result.delegation : Result.recursive; - } - } - } - } - return Result.normal; - } - - if (object instanceof PsiMethod && positionMethod != null) { - final PsiMethod method = (PsiMethod)object; - if (PsiTreeUtil.isAncestor(reference, position, false) && - Comparing.equal(method.getName(), positionMethod.getName()) && - method.getParameterList().getParametersCount() == positionMethod.getParameterList().getParametersCount()) { - if (findDeepestSuper(method).equals(findDeepestSuper(positionMethod))) { - return isDelegate ? Result.delegation : Result.recursive; - } - } - } - - return Result.normal; - } - - private static boolean isPassingObjectToItself(Object object, PsiExpression qualifier, boolean delegate) { - if (object instanceof PsiThisExpression) { - return !delegate || qualifier instanceof PsiSuperExpression; - } - return qualifier instanceof PsiReferenceExpression && - object.equals(((PsiReferenceExpression)qualifier).advancedResolve(true).getElement()); - } - - @NotNull - private static PsiMethod findDeepestSuper(@NotNull final PsiMethod method) { - final PsiMethod first = DeepestSuperMethodsSearch.search(method).findFirst(); - return first == null ? method : first; - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java index 1f92244fec69..128fdc78843a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -104,7 +104,7 @@ public class ReferenceExpressionCompletionContributor { return TrueFilter.INSTANCE; } - public static void fillCompletionVariants(final JavaSmartCompletionParameters parameters, final CompletionResultSet result) { + public static void fillCompletionVariants(final JavaSmartCompletionParameters parameters, final Consumer result) { ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { final PsiElement element = parameters.getPosition(); @@ -115,7 +115,7 @@ public class ReferenceExpressionCompletionContributor { if (reference != null) { final ElementFilter filter = getReferenceFilter(element, false); for (final LookupElement item : completeFinalReference(element, reference, filter, parameters)) { - result.addElement(item); + result.consume(item); } final boolean secondTime = parameters.getInvocationCount() >= 2; @@ -180,7 +180,7 @@ public class ReferenceExpressionCompletionContributor { } private static void addSingleArrayElementAccess(PsiElement element, LookupElement item, JavaSmartCompletionParameters parameters, - CompletionResultSet result) { + Consumer result) { if (item.getObject() instanceof PsiLocalVariable) { final PsiLocalVariable variable = (PsiLocalVariable)item.getObject(); final PsiType type = variable.getType(); @@ -192,7 +192,7 @@ public class ReferenceExpressionCompletionContributor { if (dimensions.length == 1 && "1".equals(dimensions[0].getText()) && newExpression.getArrayInitializer() == null) { final String text = variable.getName() + "[0]"; final PsiExpression conversion = createExpression(text, element); - result.addElement(new ExpressionLookupItem(conversion).setIcon(variable.getIcon(Iconable.ICON_FLAG_VISIBILITY))); + result.consume(new ExpressionLookupItem(conversion).setIcon(variable.getIcon(Iconable.ICON_FLAG_VISIBILITY))); } } } @@ -204,7 +204,7 @@ public class ReferenceExpressionCompletionContributor { } private static void addSecondCompletionVariants(PsiElement element, PsiReference reference, LookupElement baseItem, - JavaSmartCompletionParameters parameters, CompletionResultSet result) { + JavaSmartCompletionParameters parameters, Consumer result) { final Object object = baseItem.getObject(); try { @@ -236,7 +236,7 @@ public class ReferenceExpressionCompletionContributor { } private static void addArrayMemberAccessors(final PsiElement element, final String prefix, final PsiType itemType, - final PsiElement qualifier, final CompletionResultSet result, PsiModifierListOwner object, + final PsiElement qualifier, final Consumer result, PsiModifierListOwner object, final PsiType expectedType) throws IncorrectOperationException { if (itemType instanceof PsiArrayType && expectedType.isAssignableFrom(((PsiArrayType)itemType).getComponentType())) { @@ -262,7 +262,7 @@ public class ReferenceExpressionCompletionContributor { editor.getCaretModel().moveToOffset(tailOffset + 1 + callSpace.length()); } }); - result.addElement(item); + result.consume(item); } } @@ -276,7 +276,7 @@ public class ReferenceExpressionCompletionContributor { return false; } - private static void addArraysAsListConversions(final PsiElement element, final String prefix, final PsiType itemType, final CompletionResultSet result, + private static void addArraysAsListConversions(final PsiElement element, final String prefix, final PsiType itemType, final Consumer result, @Nullable PsiElement qualifier, final PsiType expectedType) throws IncorrectOperationException { PsiType componentType = PsiUtil.extractIterableTypeParameter(expectedType, true); @@ -321,11 +321,11 @@ public class ReferenceExpressionCompletionContributor { PostprocessReformattingAspect.getInstance(project).doPostponedFormatting(); } }); - result.addElement(item); + result.consume(item); } private static void addToArrayConversions(final PsiElement element, final Object object, final String prefix, final PsiType itemType, - final CompletionResultSet result, @Nullable final PsiElement qualifier, + final Consumer result, @Nullable final PsiElement qualifier, final PsiType expectedType) { final String callSpace = getSpace(CodeStyleSettingsManager.getSettings(element.getProject()).SPACE_WITHIN_METHOD_CALL_PARENTHESES); final PsiType componentType = PsiUtil.extractIterableTypeParameter(itemType, true); @@ -380,7 +380,7 @@ public class ReferenceExpressionCompletionContributor { } private static void addChainedCallVariants(final PsiElement place, LookupElement qualifierItem, - final CompletionResultSet result, + final Consumer result, PsiType qualifierType, final PsiType expectedType, JavaSmartCompletionParameters parameters) throws IncorrectOperationException { final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(place.getProject()).getElementFactory(); @@ -404,7 +404,7 @@ public class ReferenceExpressionCompletionContributor { final ElementFilter filter = getReferenceFilter(place, true); for (final LookupElement item : completeFinalReference(place, mockRef, filter, parameters)) { if (shoudChain(place, varType, expectedType, item)) { - result.addElement(JavaChainLookupElement.chainElements(qualifierItem, item)); + result.consume(JavaChainLookupElement.chainElements(qualifierItem, item)); } } } @@ -454,7 +454,7 @@ public class ReferenceExpressionCompletionContributor { return true; } - private static void addToArrayConversion(final PsiElement element, final String prefix, @NonNls final String expressionString, @NonNls String presentableString, final CompletionResultSet result, PsiElement qualifier) { + private static void addToArrayConversion(final PsiElement element, final String prefix, @NonNls final String expressionString, @NonNls String presentableString, final Consumer result, PsiElement qualifier) { final boolean callSpace = CodeStyleSettingsManager.getSettings(element.getProject()).SPACE_WITHIN_METHOD_CALL_PARENTHESES; final PsiExpression conversion; try { @@ -490,7 +490,7 @@ public class ReferenceExpressionCompletionContributor { PostprocessReformattingAspect.getInstance(project).doPostponedFormatting(); } }); - result.addElement(item); + result.consume(item); } private static boolean isEmptyArrayInitializer(@Nullable PsiElement element) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SameWordsWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/SameWordsWeigher.java deleted file mode 100644 index ca315e8df12c..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SameWordsWeigher.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.ExpectedTypeInfo; -import com.intellij.codeInsight.ExpectedTypeInfoImpl; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.psi.codeStyle.NameUtil; -import gnu.trove.THashSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * @author peter -*/ -public class SameWordsWeigher extends CompletionWeigher { - - public Comparable weigh(@NotNull final LookupElement item, @NotNull final CompletionLocation location) { - if (location == null) { - return null; - } - final Object object = item.getObject(); - - final String name = JavaCompletionUtil.getLookupObjectName(object); - final ExpectedTypeInfo[] myExpectedInfos = JavaCompletionUtil.EXPECTED_TYPES.getValue(location); - if (name != null && myExpectedInfos != null) { - int max = 0; - final List wordsNoDigits = NameUtil.nameToWordsLowerCase(JavaCompletionUtil.truncDigits(name)); - for (ExpectedTypeInfo myExpectedInfo : myExpectedInfos) { - String expectedName = ((ExpectedTypeInfoImpl)myExpectedInfo).expectedName; - if (expectedName != null) { - final THashSet set = new THashSet(NameUtil.nameToWordsLowerCase(JavaCompletionUtil.truncDigits(expectedName))); - set.retainAll(wordsNoDigits); - max = Math.max(max, set.size()); - } - } - return max; - } - return 0; - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java index ce4ed9e3f2e6..3b27d56ae50a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java @@ -8,7 +8,6 @@ import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; -import com.intellij.openapi.util.Key; import com.intellij.patterns.PlatformPatterns; import com.intellij.patterns.PsiElementPattern; import com.intellij.psi.*; @@ -16,9 +15,11 @@ import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.impl.source.PostprocessReformattingAspect; +import com.intellij.psi.impl.source.tree.java.PsiEmptyExpressionImpl; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author peter @@ -27,58 +28,101 @@ class SmartCastProvider extends CompletionProvider { static final PsiElementPattern.Capture INSIDE_TYPECAST_TYPE = PlatformPatterns.psiElement().afterLeaf( PlatformPatterns.psiElement().withText("(").withParent( PsiTypeCastExpression.class)); - public static final Key TYPE_CAST = Key.create("TYPE_CAST"); protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { - for (final ExpectedTypeInfo type : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { - if (type.getType() == PsiType.VOID) { + for (final ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { + final PsiElement originalPosition = parameters.getOriginalPosition(); + final boolean overwrite = INSIDE_TYPECAST_TYPE.accepts(originalPosition); + + PsiType type = info.getDefaultType(); + if (type instanceof PsiWildcardType) { + type = ((PsiWildcardType)type).getBound(); + } + + if (type == null || type == PsiType.VOID) { continue; } - final boolean overwrite = INSIDE_TYPECAST_TYPE.accepts(parameters.getOriginalPosition()); - - final LookupElement item = AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE.applyPolicy(new LookupElementDecorator( - PsiTypeLookupItem.createLookupItem(type.getDefaultType(), parameters.getPosition())) { - - @Override - public void handleInsert(InsertionContext context) { - FeatureUsageTracker.getInstance().triggerFeatureUsed("editing.completion.smarttype.casting"); - - final Editor editor = context.getEditor(); - final Document document = editor.getDocument(); - if (overwrite) { - document.deleteString(context.getSelectionEndOffset(), - context.getOffsetMap().getOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET)); + result.addElement(createSmartCastElement(parameters, overwrite, type)); + if (type instanceof PsiPrimitiveType) { + final PsiType castedType = getCastedExpressionType(originalPosition); + if (castedType != null && !(castedType instanceof PsiPrimitiveType)) { + final PsiClassType boxedType = ((PsiPrimitiveType)type).getBoxedType(originalPosition); + if (boxedType != null) { + result.addElement(createSmartCastElement(parameters, overwrite, boxedType)); } - - final CodeStyleSettings csSettings = CodeStyleSettingsManager.getSettings(context.getProject()); - final int oldTail = context.getTailOffset(); - context.setTailOffset(RParenthTailType.addRParenth(editor, oldTail, csSettings.SPACE_WITHIN_CAST_PARENTHESES)); - - //todo let the delegate handle insertion itself - final LookupItem typeItem = getDelegate(); - final InsertionContext typeContext = CompletionUtil.newContext(context, typeItem, context.getStartOffset(), oldTail); - new DefaultInsertHandler().handleInsert(typeContext, typeItem); - final PsiTypeCastExpression castExpression = - PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiTypeCastExpression.class, false); - if (castExpression != null) { - final PsiTypeElement typeElement = castExpression.getCastType(); - if (typeElement != null) { - CodeStyleManager.getInstance(context.getProject()).reformat(typeElement); - } - } - - PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting(); - if (csSettings.SPACE_AFTER_TYPE_CAST) { - context.setTailOffset(TailType.insertChar(editor, context.getTailOffset(), ' ')); - } - - editor.getCaretModel().moveToOffset(context.getTailOffset()); - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } - }); - item.putUserData(TYPE_CAST, Boolean.TRUE); - result.addElement(item); + } } } + + @Nullable + private static PsiType getCastedExpressionType(PsiElement originalPosition) { + if (INSIDE_TYPECAST_TYPE.accepts(originalPosition)) { + final PsiTypeCastExpression cast = PsiTreeUtil.getParentOfType(originalPosition, PsiTypeCastExpression.class); + if (cast != null) { + final PsiExpression operand = cast.getOperand(); + return operand == null ? null : operand.getType(); + } + } + final PsiParenthesizedExpression parens = PsiTreeUtil.getParentOfType(originalPosition, PsiParenthesizedExpression.class, true, PsiStatement.class); + if (parens != null) { + final PsiExpression rightSide = parens.getExpression(); + if (rightSide != null) { + return rightSide.getType(); + } + PsiElement next = parens.getNextSibling(); + while (next != null && (next instanceof PsiEmptyExpressionImpl || next instanceof PsiErrorElement || next instanceof PsiWhiteSpace)) { + next = next.getNextSibling(); + } + if (next instanceof PsiExpression) { + return ((PsiExpression)next).getType(); + } + return null; + } + return null; + } + + private static LookupElement createSmartCastElement(final CompletionParameters parameters, final boolean overwrite, final PsiType type) { + return AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE.applyPolicy(new LookupElementDecorator( + PsiTypeLookupItem.createLookupItem(type, parameters.getPosition())) { + + @Override + public void handleInsert(InsertionContext context) { + FeatureUsageTracker.getInstance().triggerFeatureUsed("editing.completion.smarttype.casting"); + + final Editor editor = context.getEditor(); + final Document document = editor.getDocument(); + if (overwrite) { + document.deleteString(context.getSelectionEndOffset(), + context.getOffsetMap().getOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET)); + } + + final CodeStyleSettings csSettings = CodeStyleSettingsManager.getSettings(context.getProject()); + final int oldTail = context.getTailOffset(); + context.setTailOffset(RParenthTailType.addRParenth(editor, oldTail, csSettings.SPACE_WITHIN_CAST_PARENTHESES)); + + //todo let the delegate handle insertion itself + final LookupItem typeItem = getDelegate(); + final InsertionContext typeContext = CompletionUtil.newContext(context, typeItem, context.getStartOffset(), oldTail); + new DefaultInsertHandler().handleInsert(typeContext, typeItem); + final PsiTypeCastExpression castExpression = + PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiTypeCastExpression.class, false); + if (castExpression != null) { + final PsiTypeElement typeElement = castExpression.getCastType(); + if (typeElement != null) { + CodeStyleManager.getInstance(context.getProject()).reformat(typeElement); + } + } + + PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting(); + if (csSettings.SPACE_AFTER_TYPE_CAST) { + context.setTailOffset(TailType.insertChar(editor, context.getTailOffset(), ' ')); + } + + editor.getCaretModel().moveToOffset(context.getTailOffset()); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + } + }); + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMembersWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMembersWeigher.java deleted file mode 100644 index 1ae1ce9513ff..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMembersWeigher.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.psi.*; -import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; - -/** - * @author peter - */ -public class StaticMembersWeigher extends CompletionWeigher { - public Comparable weigh(@NotNull LookupElement element, @NotNull CompletionLocation loc) { - if (loc.getCompletionType() != CompletionType.BASIC) return 0; - - // cheap weigher applicability goes first - final Object o = element.getObject(); - if (!(o instanceof PsiMember)) return 0; - - final PsiElement position = loc.getCompletionParameters().getPosition(); - if (PsiTreeUtil.getParentOfType(position, PsiDocComment.class) != null) return 0; - if (position.getParent() instanceof PsiReferenceExpression) { - final PsiReferenceExpression refExpr = (PsiReferenceExpression)position.getParent(); - final PsiElement qualifier = refExpr.getQualifier(); - if (qualifier == null) { - return 0; - } - if (!(qualifier instanceof PsiJavaCodeReferenceElement) || !(((PsiJavaCodeReferenceElement)qualifier).resolve() instanceof PsiClass)) { - return 0; - } - } - - if (((PsiMember)o).hasModifierProperty(PsiModifier.STATIC)) { - if (o instanceof PsiMethod) return 5; - if (o instanceof PsiField) return 4; - } - - if (o instanceof PsiClass) { - //if (((PsiClass) o).getContainingClass() != null) return 2; - return 3; - } - - //instance method or field - return 5; - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java index dc79715dc74b..b0cd28cf2d2a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java @@ -26,14 +26,13 @@ import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.scope.BaseScopeProcessor; import com.intellij.psi.scope.ElementClassHint; import com.intellij.psi.scope.JavaScopeProcessorEvent; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; /** * Created by IntelliJ IDEA. @@ -58,8 +57,9 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme private PsiClass myQualifierClass = null; private final Condition myMatcher; private final boolean myCheckAccess; + private final Set myNonInitializedFields = new HashSet(); - public JavaCompletionProcessor(PsiElement element, ElementFilter filter, final boolean checkAccess, @Nullable Condition nameCondition) { + public JavaCompletionProcessor(PsiElement element, ElementFilter filter, final boolean checkAccess, boolean checkInitialized, @Nullable Condition nameCondition) { myCheckAccess = checkAccess; mySettings = CodeInsightSettings.getInstance(); myResults = new ArrayList(); @@ -102,6 +102,65 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme } } } + + if (checkInitialized) { + myNonInitializedFields.addAll(getNonInitializedFields(element)); + } + } + + private static Set getNonInitializedFields(PsiElement element) { + final PsiStatement statement = PsiTreeUtil.getParentOfType(element, PsiStatement.class); + final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class, true, PsiClass.class); + if (statement == null || method == null || !method.isConstructor()) { + return Collections.emptySet(); + } + + PsiElement parent = element.getParent(); + while (parent != statement) { + PsiElement next = parent.getParent(); + if (next instanceof PsiAssignmentExpression && parent == ((PsiAssignmentExpression)next).getLExpression()) { + return Collections.emptySet(); + } + if (parent instanceof PsiReferenceExpression && next instanceof PsiExpressionStatement) { + return Collections.emptySet(); + } + parent = next; + } + + final Set fields = new HashSet(); + final PsiClass containingClass = method.getContainingClass(); + assert containingClass != null; + for (PsiField field : containingClass.getFields()) { + if (!field.hasModifierProperty(PsiModifier.STATIC) && field.getInitializer() == null) { + fields.add(field); + } + } + + method.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + if (expression.getTextRange().getStartOffset() < statement.getTextRange().getStartOffset()) { + final PsiExpression lExpression = expression.getLExpression(); + if (lExpression instanceof PsiReferenceExpression) { + //noinspection SuspiciousMethodCalls + fields.remove(((PsiReferenceExpression)lExpression).resolve()); + } + } + super.visitAssignmentExpression(expression); + } + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + if (expression.getTextRange().getStartOffset() < statement.getTextRange().getStartOffset()) { + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression.textMatches("this")) { + fields.clear(); + } + } + super.visitMethodCallExpression(expression); + } + }); + return fields; } public void handleEvent(Event event, Object associated){ @@ -113,19 +172,24 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme } } - public boolean execute(PsiElement element, ResolveState state){ - if(!(element instanceof PsiClass) && element instanceof PsiModifierListOwner){ + public boolean execute(PsiElement element, ResolveState state) { + //noinspection SuspiciousMethodCalls + if (myNonInitializedFields.contains(element)) { + return true; + } + + if (!(element instanceof PsiClass) && element instanceof PsiModifierListOwner) { PsiModifierListOwner modifierListOwner = (PsiModifierListOwner)element; - if(myStatic){ - if(!modifierListOwner.hasModifierProperty(PsiModifier.STATIC)){ + if (myStatic) { + if (!modifierListOwner.hasModifierProperty(PsiModifier.STATIC)) { // we don't need non static method in static context. return true; } } - else{ - if(!mySettings.SHOW_STATIC_AFTER_INSTANCE - && modifierListOwner.hasModifierProperty(PsiModifier.STATIC) - && !myMembersFlag){ + else { + if (!mySettings.SHOW_STATIC_AFTER_INSTANCE + && modifierListOwner.hasModifierProperty(PsiModifier.STATIC) + && !myMembersFlag) { // according settings we don't need to process such fields/methods return true; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index 43a6890bfb3b..233825ad6688 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -16,16 +16,23 @@ package com.intellij.codeInsight.daemon.impl.analysis; import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.daemon.JavaErrorMessages; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; +import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction; +import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -221,7 +228,7 @@ public class AnnotationsHighlightUtil { return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, typeElement, JavaErrorMessages.message("annotation.invalid.annotation.member.type")); } - public static HighlightInfo checkApplicability(PsiAnnotation annotation) { + public static HighlightInfo checkApplicability(final PsiAnnotation annotation) { PsiAnnotationOwner owner = annotation.getOwner(); if (!(owner instanceof PsiModifierList || owner instanceof PsiTypeElement || owner instanceof PsiMethodReceiver || owner instanceof PsiTypeParameter)) return null; PsiElement member = ((PsiElement)owner).getParent(); @@ -231,7 +238,9 @@ public class AnnotationsHighlightUtil { String description = JavaErrorMessages.message("annotation.not.applicable", nameRef.getText(), JavaErrorMessages.message("annotation.target." + elementTypeFields[0])); - return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, nameRef, description); + final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, nameRef, description); + QuickFixAction.registerQuickFixAction(highlightInfo, new DeleteNotApplicableAnnotationAction(annotation)); + return highlightInfo; } public static boolean isAnnotationApplicableTo(PsiAnnotation annotation, boolean strict, String... elementTypeFields) { @@ -445,4 +454,40 @@ public class AnnotationsHighlightUtil { return classType.equalsToText("java.lang.Class") || classType.equalsToText("java.lang.String") ? Boolean.TRUE : Boolean.FALSE; } } + + private static class DeleteNotApplicableAnnotationAction implements IntentionAction { + private final PsiAnnotation myAnnotation; + + public DeleteNotApplicableAnnotationAction(PsiAnnotation annotation) { + myAnnotation = annotation; + } + + @NotNull + @Override + public String getText() { + return "Remove"; + } + + @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 { + if (!CodeInsightUtilBase.prepareFileForWrite(file)) return; + myAnnotation.delete(); + } + + @Override + public boolean startInWriteAction() { + return true; + } + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index d915d14f4bc3..2d272ee14ae3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -107,6 +107,22 @@ public class GenericsHighlightUtil { } } + PsiDiamondType.DiamondInferenceResult inferenceResult = null; + PsiTypeElement[] referenceElements = null; + if (referenceParameterList != null) { + referenceElements = referenceParameterList.getTypeParameterElements(); + if (referenceElements.length == 1 && referenceElements[0].getType() instanceof PsiDiamondType) { + if (!typeParameterListOwner.hasTypeParameters()) { + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceElements[0], "Diamond operator is not applicable for non-parameterized types"); + } + inferenceResult = ((PsiDiamondType)referenceElements[0].getType()).resolveInferredTypes(); + final String errorMessage = inferenceResult.getErrorMessage(); + if (errorMessage != null) { + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceElements[0], errorMessage); + } + } + } + final PsiTypeParameter[] typeParameters = typeParameterListOwner.getTypeParameters(); final int targetParametersNum = typeParameters.length; final int refParametersNum = referenceParameterList == null ? 0 : referenceParameterList.getTypeArguments().length; @@ -140,9 +156,8 @@ public class GenericsHighlightUtil { // bounds check if (targetParametersNum > 0 && refParametersNum != 0) { - final PsiTypeElement[] referenceElements = referenceParameterList.getTypeParameterElements(); - if (referenceElements.length == 1 && referenceElements[0].getType() instanceof PsiDiamondType) { - final PsiType[] types = ((PsiDiamondType)referenceElements[0].getType()).getInferredTypes(); + if (inferenceResult != null) { + final PsiType[] types = inferenceResult.getTypes(); for (int i = 0; i < typeParameters.length; i++) { final PsiType type = types[i]; final HighlightInfo highlightInfo = checkTypeParameterWithinItsBound(typeParameters[i], substitutor, type, referenceElements[0]); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java index 9afe6a9b3815..83704c2c63be 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java @@ -13,15 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * Created by IntelliJ IDEA. - * User: cdr - * Date: Aug 8, 2002 - * Time: 5:55:01 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ package com.intellij.codeInsight.daemon.impl.analysis; import com.intellij.codeInsight.daemon.JavaErrorMessages; @@ -43,9 +34,14 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +/** + * @author cdr + * Date: Aug 8, 2002 + */ public class HighlightControlFlowUtil { private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance(); + private HighlightControlFlowUtil() { } @Nullable public static HighlightInfo checkMissingReturnStatement(PsiMethod method) { @@ -297,7 +293,7 @@ public class HighlightControlFlowUtil { topBlock = JspPsiUtil.isInJspFile(scope) && scope instanceof PsiFile ? scope : PsiUtil.getTopLevelEnclosingCodeBlock(expression, scope); if (variable instanceof PsiField) { - // non final field already initalized with default value + // non final field already initialized with default value if (!variable.hasModifierProperty(PsiModifier.FINAL)) return null; // final field may be initialized in ctor or class initializer only // if we're inside non-ctr method, skip it @@ -314,9 +310,9 @@ public class HighlightControlFlowUtil { if (parent instanceof PsiMethod) { PsiMethod constructor = (PsiMethod)parent; if (!parent.getManager().areElementsEquivalent(constructor.getContainingClass(), ((PsiField)variable).getContainingClass())) return null; - // static variables already initalized in class initalizers + // static variables already initialized in class initializers if (variable.hasModifierProperty(PsiModifier.STATIC)) return null; - // as a last chance, field may be initalized in this() call + // as a last chance, field may be initialized in this() call final List redirectedConstructors = getChainedConstructors(constructor); for (int j = 0; redirectedConstructors != null && j < redirectedConstructors.size(); j++) { PsiMethod redirectedConstructor = redirectedConstructors.get(j); @@ -338,7 +334,7 @@ public class HighlightControlFlowUtil { aClass = classInitializer.getContainingClass(); } else { - // field reference outside codeblock + // field reference outside code block // check variable initialized before its usage final PsiField field = (PsiField)variable; @@ -356,7 +352,7 @@ public class HighlightControlFlowUtil { && variableDefinitelyAssignedIn(variable, constructor.getBody())) { return null; } - // as a last chance, field may be initalized in this() call + // as a last chance, field may be initialized in this() call final List redirectedConstructors = getChainedConstructors(constructor); for (int j = 0; redirectedConstructors != null && j < redirectedConstructors.size(); j++) { PsiMethod redirectedConstructor = redirectedConstructors.get(j); @@ -371,13 +367,13 @@ public class HighlightControlFlowUtil { } if (aClass != null) { - // field may be initialized in class initalizer + // field may be initialized in class initializer final PsiClassInitializer[] initializers = aClass.getInitializers(); for (PsiClassInitializer initializer : initializers) { PsiCodeBlock body = initializer.getBody(); if (body == block) break; // variable referenced in initializer must be initialized in initializer preceding assignment - // varaibel refernced in field initializer or in class initializier + // variable referenced in field initializer or in class initializer boolean shouldCheckInitializerOrder = block == null || block.getParent() instanceof PsiClassInitializer; if (shouldCheckInitializerOrder && startOffset < initializer.getTextRange().getStartOffset()) continue; if (initializer.hasModifierProperty(PsiModifier.STATIC) @@ -449,6 +445,7 @@ public class HighlightControlFlowUtil { } + @Nullable public static HighlightInfo checkFinalVariableMightAlreadyHaveBeenAssignedTo(PsiVariable variable, PsiReferenceExpression expression, Map> finalVarProblems) { @@ -473,7 +470,7 @@ public class HighlightControlFlowUtil { final PsiField field = (PsiField)variable; final PsiClass aClass = field.getContainingClass(); if (aClass == null) return null; - // field can get assigned in other field inititializers + // field can get assigned in other field initializers final PsiField[] fields = aClass.getFields(); boolean isFieldStatic = field.hasModifierProperty(PsiModifier.STATIC); for (PsiField psiField : fields) { @@ -565,7 +562,8 @@ public class HighlightControlFlowUtil { } - public static HighlightInfo checkFinalVariableInitalizedInLoop(PsiReferenceExpression expression, PsiElement resolved) { + @Nullable + public static HighlightInfo checkFinalVariableInitializedInLoop(PsiReferenceExpression expression, PsiElement resolved) { if (ControlFlowUtil.isVariableAssignedInLoop(expression, resolved)) { String description = JavaErrorMessages.message("variable.assigned.in.loop", ((PsiVariable)resolved).getName()); final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo( @@ -580,6 +578,7 @@ public class HighlightControlFlowUtil { } + @Nullable public static HighlightInfo checkCannotWriteToFinal(PsiExpression expression) { PsiReferenceExpression reference = null; if (expression instanceof PsiAssignmentExpression) { @@ -659,6 +658,7 @@ public class HighlightControlFlowUtil { } + @Nullable static HighlightInfo checkVariableMustBeFinal(PsiVariable variable, PsiJavaCodeReferenceElement context) { if (variable.hasModifierProperty(PsiModifier.FINAL)) return null; final PsiClass innerClass = getInnerClassVariableReferencedFrom(variable, context); @@ -672,23 +672,30 @@ public class HighlightControlFlowUtil { return null; } + @Nullable public static PsiClass getInnerClassVariableReferencedFrom(PsiVariable variable, PsiElement context) { - PsiElement scope; - if (variable instanceof PsiLocalVariable) { - scope = variable.getParent().getParent(); // code block or for statement + PsiElement[] scope; + if (variable instanceof PsiScopedLocalVariable) { + scope = ((PsiScopedLocalVariable)variable).getDeclarationScope(); + } + else if (variable instanceof PsiLocalVariable) { + scope = new PsiElement[]{variable.getParent().getParent()}; // code block or for statement } else if (variable instanceof PsiParameter) { - scope = ((PsiParameter)variable).getDeclarationScope(); + scope = new PsiElement[]{((PsiParameter)variable).getDeclarationScope()}; } else { - scope = variable.getParent(); + scope = new PsiElement[]{variable.getParent()}; } - if (scope.getContainingFile() != context.getContainingFile()) return null; + if (scope.length < 1 || scope[0].getContainingFile() != context.getContainingFile()) return null; PsiElement parent = context.getParent(); PsiElement prevParent = context; + outer: while (parent != null) { - if (parent.equals(scope)) break; + for (PsiElement scopeElement : scope) { + if (parent.equals(scopeElement)) break outer; + } if (parent instanceof PsiClass && !(prevParent instanceof PsiExpressionList && parent instanceof PsiAnonymousClass)) { return (PsiClass)parent; } @@ -699,6 +706,7 @@ public class HighlightControlFlowUtil { } + @Nullable public static HighlightInfo checkInitializerCompleteNormally(PsiClassInitializer initializer) { final PsiCodeBlock body = initializer.getBody(); // unhandled exceptions already reported diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index ec903511c0e1..70db6cf0ce8b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -36,6 +36,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod; import com.intellij.psi.javadoc.PsiDocComment; @@ -45,6 +46,7 @@ import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.xml.util.XmlStringUtil; import gnu.trove.THashMap; @@ -73,8 +75,7 @@ public class HighlightUtil { @NonNls private static final String SERIAL_PERSISTENT_FIELDS_FIELD_NAME = "serialPersistentFields"; private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance(); - private HighlightUtil() { - } + private HighlightUtil() { } static { ourClassIncompatibleModifiers = new THashMap>(8); @@ -345,6 +346,7 @@ public class HighlightUtil { } + @Nullable static HighlightInfo checkVariableExpected(PsiExpression expression) { PsiExpression lValue; if (expression instanceof PsiAssignmentExpression) { @@ -543,33 +545,39 @@ public class HighlightUtil { return errorResult; } - public static String getUnhandledExceptionsDescriptor(Collection unhandledExceptions) { - StringBuilder exceptionsText = new StringBuilder(); - for (PsiClassType unhandledException : unhandledExceptions) { - if (exceptionsText.length() != 0) exceptionsText.append(", "); - exceptionsText.append(formatType(unhandledException)); - } - - return JavaErrorMessages.message("unhandled.exceptions", exceptionsText.toString(), unhandledExceptions.size()); + public static String getUnhandledExceptionsDescriptor(final Collection unhandled) { + return getUnhandledExceptionsDescriptor(unhandled, null); } + private static String getUnhandledExceptionsDescriptor(final Collection unhandled, final String source) { + final String exceptions = StringUtil.join(unhandled, new Function() { + @Override public String fun(PsiClassType type) { return formatType(type); } + }, ", "); + return source != null ? JavaErrorMessages.message("unhandled.close.exceptions", exceptions, unhandled.size(), source) + : JavaErrorMessages.message("unhandled.exceptions", exceptions, unhandled.size()); + } @Nullable static HighlightInfo checkVariableAlreadyDefined(PsiVariable variable) { if (variable instanceof ExternallyDefinedPsiElement) return null; boolean isIncorrect = false; PsiIdentifier identifier = variable.getNameIdentifier(); + assert identifier != null : variable; String name = variable.getName(); if (variable instanceof PsiLocalVariable || variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiCatchSection || variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) { - PsiElement scope = PsiTreeUtil.getParentOfType(variable, PsiFile.class, PsiMethod.class, PsiClassInitializer.class); - VariablesNotProcessor proc = new VariablesNotProcessor(variable, false){ + PsiElement scope = PsiTreeUtil.getParentOfType(variable, PsiFile.class, PsiMethod.class, PsiClassInitializer.class, PsiResourceList.class); + VariablesNotProcessor proc = new VariablesNotProcessor(variable, false) { protected boolean check(final PsiVariable var, final ResolveState state) { return (var instanceof PsiLocalVariable || var instanceof PsiParameter) && super.check(var, state); } }; PsiScopesUtil.treeWalkUp(proc, identifier, scope); + if (scope instanceof PsiResourceList && proc.size() == 0) { + scope = PsiTreeUtil.getParentOfType(variable, PsiFile.class, PsiMethod.class, PsiClassInitializer.class); + PsiScopesUtil.treeWalkUp(proc, identifier, scope); + } if (proc.size() > 0) { isIncorrect = true; } @@ -631,26 +639,47 @@ public class HighlightUtil { } - public static HighlightInfo checkUnhandledExceptions(PsiElement element, TextRange fixRange) { - List unhandledExceptions = ExceptionUtil.getUnhandledExceptions(element); - HighlightInfo errorResult = null; - if (!unhandledExceptions.isEmpty()) { - if (fixRange == null) { - fixRange = element.getTextRange(); - } - HighlightInfoType highlightType = getUnhandledExceptionHighlightType(element); - if (highlightType == null) return null; - errorResult = HighlightInfo.createHighlightInfo(highlightType, fixRange, getUnhandledExceptionsDescriptor(unhandledExceptions)); - QuickFixAction.registerQuickFixAction(errorResult, new AddExceptionToCatchFix()); - QuickFixAction.registerQuickFixAction(errorResult, new AddExceptionToThrowsFix(element)); - QuickFixAction.registerQuickFixAction(errorResult, new SurroundWithTryCatchFix(element)); - if (unhandledExceptions.size() == 1) { - QuickFixAction.registerQuickFixAction(errorResult, new GeneralizeCatchFix(element, unhandledExceptions.get(0))); - } - } + @Nullable + public static HighlightInfo checkUnhandledExceptions(final PsiElement element, TextRange fixRange) { + final List unhandledExceptions = ExceptionUtil.getUnhandledExceptions(element); + if (unhandledExceptions.isEmpty()) return null; + + final HighlightInfoType highlightType = getUnhandledExceptionHighlightType(element); + if (highlightType == null) return null; + + if (fixRange == null) fixRange = element.getTextRange(); + final String description = getUnhandledExceptionsDescriptor(unhandledExceptions); + final HighlightInfo errorResult = HighlightInfo.createHighlightInfo(highlightType, fixRange, description); + registerUnhandledExceptionFixes(element, errorResult, unhandledExceptions); return errorResult; } + @Nullable + public static HighlightInfo checkUnhandledCloserExceptions(final PsiResource resource) { + final List unhandled = ExceptionUtil.getUnhandledCloserExceptions(resource, null); + if (unhandled.isEmpty()) return null; + + final HighlightInfoType highlightType = getUnhandledExceptionHighlightType(resource); + if (highlightType == null) return null; + + final String description = getUnhandledExceptionsDescriptor(unhandled, "auto-closeable resource"); + final HighlightInfo highlight = HighlightInfo.createHighlightInfo(highlightType, resource, description); + registerUnhandledExceptionFixes(resource, highlight, unhandled); + return highlight; + } + + private static void registerUnhandledExceptionFixes(final PsiElement element, + final HighlightInfo errorResult, + final List unhandled) { + QuickFixAction.registerQuickFixAction(errorResult, new AddExceptionToCatchFix()); + QuickFixAction.registerQuickFixAction(errorResult, new AddExceptionToThrowsFix(element)); + QuickFixAction.registerQuickFixAction(errorResult, new SurroundWithTryCatchFix(element)); + if (unhandled.size() == 1) { + QuickFixAction.registerQuickFixAction(errorResult, new GeneralizeCatchFix(element, unhandled.get(0))); + } + } + + @Nullable private static HighlightInfoType getUnhandledExceptionHighlightType(final PsiElement element) { if (!JspPsiUtil.isInJspFile(element)) { return HighlightInfoType.UNHANDLED_EXCEPTION; @@ -697,6 +726,7 @@ public class HighlightUtil { } + @Nullable static HighlightInfo checkIllegalModifierCombination(PsiKeyword keyword, PsiModifierList modifierList) { @Modifier String modifier = keyword.getText(); String incompatible = getIncompatibleModifier(modifier, modifierList); @@ -864,13 +894,11 @@ public class HighlightUtil { assert tryBlock != null : statement; thrownTypes.addAll(ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock)); - final PsiParameterList resources = statement.getResourceList(); + final PsiResourceList resources = statement.getResourceList(); if (resources != null) { thrownTypes.addAll(ExceptionUtil.collectUnhandledExceptions(resources, resources)); } - // todo: add exceptions from resource's close() method - final PsiType caughtType = parameter.getType(); if (caughtType instanceof PsiClassType) { return checkSimpleCatchParameter(parameter, thrownTypes, (PsiClassType)caughtType); @@ -950,6 +978,7 @@ public class HighlightUtil { } + @Nullable public static HighlightInfo checkSwitchSelectorType(PsiSwitchStatement statement) { PsiExpression expression = statement.getExpression(); HighlightInfo errorResult = null; @@ -1110,19 +1139,32 @@ public class HighlightUtil { @Nullable - public static HighlightInfo checkCatchParameterIsThrowable(PsiParameter parameter) { + public static HighlightInfo checkCatchParameterIsThrowable(final PsiParameter parameter) { if (parameter.getDeclarationScope() instanceof PsiCatchSection) { - PsiType type = parameter.getType(); + final PsiType type = parameter.getType(); return checkMustBeThrowable(type, parameter, true); } return null; } - public static void checkArrayInitalizer(final PsiExpression initializer, final HighlightInfoHolder holder) { - if (! (initializer instanceof PsiArrayInitializerExpression)) return; + @Nullable + public static HighlightInfo checkTryResourceIsAutoCloseable(@NotNull final PsiResource resource) { + final PsiType type = resource.getType(); + if (type == null) return null; + + final PsiElementFactory factory = JavaPsiFacade.getInstance(resource.getProject()).getElementFactory(); + final PsiClassType autoCloseable = factory.createTypeByFQClassName("java.lang.AutoCloseable", resource.getResolveScope()); + if (TypeConversionUtil.isAssignable(autoCloseable, type)) return null; + + return createIncompatibleTypeHighlightInfo(autoCloseable, type, resource.getTextRange()); + } + + @Nullable + public static Collection checkArrayInitializer(final PsiExpression initializer) { + if (! (initializer instanceof PsiArrayInitializerExpression)) return null; final PsiType arrayInitializerType = initializer.getType(); - if (! (arrayInitializerType instanceof PsiArrayType)) return; + if (! (arrayInitializerType instanceof PsiArrayType)) return null; final PsiType componentType = ((PsiArrayType) arrayInitializerType).getComponentType(); final PsiArrayInitializerExpression arrayInitializer = (PsiArrayInitializerExpression) initializer; @@ -1130,11 +1172,12 @@ public class HighlightUtil { boolean arrayTypeFixChecked = false; VariableArrayTypeFix fix = null; + final Collection result = Lists.newArrayList(); final PsiExpression[] initializers = arrayInitializer.getInitializers(); for (PsiExpression expression : initializers) { - final HighlightInfo info = checkArrayInitalizerCompatibleTypes(expression, componentType); + final HighlightInfo info = checkArrayInitializerCompatibleTypes(expression, componentType); if (info != null) { - holder.add(info); + result.add(info); if (!arrayTypeFixChecked) { final PsiType checkResult = sameType(initializers); @@ -1146,6 +1189,7 @@ public class HighlightUtil { } } } + return result; } @Nullable @@ -1157,6 +1201,7 @@ public class HighlightUtil { return null; } + @Nullable public static PsiType sameType(PsiExpression[] expressions) { PsiType type = null; for (PsiExpression expression : expressions) { @@ -1178,7 +1223,7 @@ public class HighlightUtil { } @Nullable - private static HighlightInfo checkArrayInitalizerCompatibleTypes(PsiExpression initializer, final PsiType componentType) { + private static HighlightInfo checkArrayInitializerCompatibleTypes(PsiExpression initializer, final PsiType componentType) { PsiType initializerType = initializer.getType(); if (initializerType == null) { return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, initializer, @@ -1212,16 +1257,12 @@ public class HighlightUtil { PsiVariable variable = (PsiVariable)parent; if (variable.getType() instanceof PsiArrayType) return null; } - else if (parent instanceof PsiNewExpression) { + else if (parent instanceof PsiNewExpression || parent instanceof PsiArrayInitializerExpression) { return null; } - else if (parent instanceof PsiArrayInitializerExpression) { - return null; - } - HighlightInfo info = - HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, JavaErrorMessages.message("expression.expected")); - QuickFixAction.registerQuickFixAction(info, new AddNewArrayExpressionFix(expression)); + HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, JavaErrorMessages.message("expression.expected")); + QuickFixAction.registerQuickFixAction(info, new AddNewArrayExpressionFix(expression)); return info; } @@ -1393,13 +1434,11 @@ public class HighlightUtil { if (typeOwner instanceof PsiMethod) { if (((PsiMethod)typeOwner).getReturnTypeElement() == parent) return null; } - else if (typeOwner instanceof PsiClassObjectAccessExpression && - TypeConversionUtil.isVoidType(((PsiClassObjectAccessExpression)typeOwner).getOperand().getType())) { - // like in Class c = void.class; - return null; - } - else if (typeOwner != null && PsiUtilBase.hasErrorElementChild(typeOwner)) { - // do not highlight incomplete declarations + else if (// like in Class c = void.class; + typeOwner instanceof PsiClassObjectAccessExpression && + TypeConversionUtil.isVoidType(((PsiClassObjectAccessExpression)typeOwner).getOperand().getType()) || + // do not highlight incomplete declarations + typeOwner != null && PsiUtilBase.hasErrorElementChild(typeOwner)) { return null; } else if (typeOwner instanceof JavaCodeFragment) { @@ -1510,6 +1549,7 @@ public class HighlightUtil { return checkReferenceToOurInstanceInsideThisOrSuper(expression, referencedClass, resolvedName); } + @Nullable private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper(final PsiElement expression, final PsiClass referencedClass, final String resolvedName) { @@ -1551,6 +1591,7 @@ public class HighlightUtil { return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, textRange, description); } + @Nullable public static HighlightInfo checkImplicitThisReferenceBeforeSuper(PsiClass aClass) { if (aClass instanceof PsiAnonymousClass) return null; PsiClass superClass = aClass.getSuperClass(); @@ -1589,6 +1630,7 @@ public class HighlightUtil { return element != null; } + @Nullable private static String getMethodExpressionName(PsiElement element) { if (!(element instanceof PsiMethodCallExpression)) return null; PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)element).getMethodExpression(); @@ -2082,6 +2124,7 @@ public class HighlightUtil { return aClass == null || isSerializable(aClass); } + @Nullable public static HighlightInfo checkClassReferenceAfterQualifier(final PsiReferenceExpression expression, final PsiElement resolved) { if (!(resolved instanceof PsiClass)) return null; final PsiExpression qualifier = expression.getQualifierExpression(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 9d963c68c0d2..decc5b2d7126 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -342,7 +342,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkCannotWriteToFinal(expression)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkVariableExpected(expression)); - if (!myHolder.hasErrorResults()) HighlightUtil.checkArrayInitalizer(expression, myHolder); + if (!myHolder.hasErrorResults()) myHolder.addAll(HighlightUtil.checkArrayInitializer(expression)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTernaryOperatorConditionIsBoolean(expression)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAssertOperatorTypes(expression)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSynchronizedExpressionType(expression)); @@ -820,7 +820,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) { myHolder.add(HighlightControlFlowUtil.checkFinalVariableMightAlreadyHaveBeenAssignedTo(variable, expression, myFinalVarProblems)); } - if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkFinalVariableInitalizedInLoop(expression, resolved)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkFinalVariableInitializedInLoop(expression, resolved)); } } @@ -897,8 +897,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitTryStatement(PsiTryStatement statement) { super.visitTryStatement(statement); if (!myHolder.hasErrorResults()) { - PsiParameter[] parameters = statement.getCatchBlockParameters(); - for (PsiParameter parameter : parameters) { + for (PsiParameter parameter : statement.getCatchBlockParameters()) { myHolder.addAll(HighlightUtil.checkExceptionThrownInTry(parameter)); myHolder.add(HighlightUtil.checkCatchParameterIsThrowable(parameter)); myHolder.add(GenericsHighlightUtil.checkCatchParameterIsClass(parameter)); @@ -906,6 +905,14 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } + @Override + public void visitResource(final PsiResource resource) { + myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource)); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resource)); + } + } + @Override public void visitTypeElement(PsiTypeElement type) { if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIllegalType(type)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkReferenceTypeUsedAsTypeArgument(type)); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodQuickFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodQuickFix.java index b232cb7dce86..2826cec4c910 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodQuickFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodQuickFix.java @@ -24,7 +24,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.impl.JavaPsiFacadeEx; import com.intellij.psi.util.PsiFormatUtil; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; @@ -61,23 +60,18 @@ public class CreateMethodQuickFix implements LocalQuickFix { } public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { - try { - if (!CodeInsightUtilBase.preparePsiElementForWrite(myTargetClass.getContainingFile())) return; + if (!CodeInsightUtilBase.preparePsiElementForWrite(myTargetClass.getContainingFile())) return; - PsiMethod method = createMethod(project); - List> arguments = - ContainerUtil.map2List(method.getParameterList().getParameters(), new Function>() { - public Pair fun(PsiParameter psiParameter) { - return Pair.create(null, psiParameter.getType()); - } - }); + PsiMethod method = createMethod(project); + List> arguments = + ContainerUtil.map2List(method.getParameterList().getParameters(), new Function>() { + public Pair fun(PsiParameter psiParameter) { + return Pair.create(null, psiParameter.getType()); + } + }); - method = (PsiMethod)JavaCodeStyleManager.getInstance(project).shortenClassReferences((PsiMethod)myTargetClass.add(method)); - CreateMethodFromUsageFix.doCreate(myTargetClass, method, arguments, PsiSubstitutor.EMPTY, ExpectedTypeInfo.EMPTY_ARRAY, method); - } - catch (IncorrectOperationException e) { - throw new RuntimeException(e); - } + method = (PsiMethod)JavaCodeStyleManager.getInstance(project).shortenClassReferences((PsiMethod)myTargetClass.add(method)); + CreateMethodFromUsageFix.doCreate(myTargetClass, method, arguments, PsiSubstitutor.EMPTY, ExpectedTypeInfo.EMPTY_ARRAY, method); } private PsiMethod createMethod(Project project) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java index 0c1b429466db..9c9e93c96193 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java @@ -22,6 +22,7 @@ import com.intellij.codeInsight.daemon.impl.actions.AddImportAction; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.compiler.ModuleCompilerUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.Result; @@ -42,8 +43,6 @@ import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.compiler.ModuleCompilerUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -72,12 +71,7 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix { } public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { - try { - invoke(project, null, descriptor.getPsiElement().getContainingFile()); - } - catch (IncorrectOperationException e) { - throw new RuntimeException(e); - } + invoke(project, null, descriptor.getPsiElement().getContainingFile()); } @Nullable diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java index 18dd2f6283bc..0e6cd0ae748e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java @@ -27,21 +27,19 @@ import com.intellij.psi.scope.processor.VariablesNotProcessor; import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** - * Created by IntelliJ IDEA. - * User: cdr + * @author cdr * Date: Nov 20, 2002 - * Time: 3:01:25 PM - * To change this template use Options | File Templates. */ public class ReuseVariableDeclarationFix implements IntentionAction { - private final PsiVariable variable; - private final PsiIdentifier identifier; + private final PsiVariable myVariable; + private final PsiIdentifier myIdentifier; - public ReuseVariableDeclarationFix(PsiVariable variable, PsiIdentifier identifier) { - this.variable = variable; - this.identifier = identifier; + public ReuseVariableDeclarationFix(final PsiVariable variable, final PsiIdentifier identifier) { + this.myVariable = variable; + this.myIdentifier = identifier; } @NotNull @@ -51,55 +49,63 @@ public class ReuseVariableDeclarationFix implements IntentionAction { @NotNull public String getText() { - return QuickFixBundle.message("reuse.variable.declaration.text", variable.getName()); + return QuickFixBundle.message("reuse.variable.declaration.text", myVariable.getName()); } - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - - PsiVariable previousVariable = findPreviousVariable(); - return - variable != null - && variable.isValid() - && variable instanceof PsiLocalVariable - && previousVariable != null - && Comparing.equal(previousVariable.getType(), variable.getType()) - && identifier != null - && identifier.isValid() - && variable.getManager().isInProject(variable); + public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) { + final PsiVariable previousVariable = findPreviousVariable(); + return myVariable != null && + myVariable.isValid() && + myVariable instanceof PsiLocalVariable && + !(myVariable.getParent() instanceof PsiResource && myVariable.getInitializer() == null) && + previousVariable != null && + Comparing.equal(previousVariable.getType(), myVariable.getType()) && + myIdentifier != null && + myIdentifier.isValid() && + myVariable.getManager().isInProject(myVariable); } - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - PsiVariable refVariable = findPreviousVariable(); + public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { + final PsiVariable refVariable = findPreviousVariable(); if (refVariable == null) return; - if (!CodeInsightUtil.preparePsiElementsForWrite(variable, refVariable)) return; - PsiUtil.setModifierProperty(refVariable, PsiModifier.FINAL, false); - if (variable.getInitializer() == null) { - variable.delete(); + + if (!CodeInsightUtil.preparePsiElementsForWrite(myVariable, refVariable)) return; + + final PsiExpression initializer = myVariable.getInitializer(); + if (initializer == null) { + myVariable.delete(); return; } - PsiDeclarationStatement declaration = (PsiDeclarationStatement) variable.getParent(); - PsiElementFactory factory = JavaPsiFacade.getInstance(variable.getProject()).getElementFactory(); - PsiStatement statement = factory.createStatementFromText(variable.getName() + " = " + variable.getInitializer().getText()+";", variable); - declaration.replace(statement); + + PsiUtil.setModifierProperty(refVariable, PsiModifier.FINAL, false); + + final PsiElementFactory factory = JavaPsiFacade.getInstance(myVariable.getProject()).getElementFactory(); + final PsiElement replacement; + final PsiElement parent = myVariable.getParent(); + if (parent instanceof PsiResource) { + replacement = factory.createResourceFromText(myVariable.getName() + " = " + initializer.getText(), null); + } + else { + replacement = factory.createStatementFromText(myVariable.getName() + " = " + initializer.getText() + ";", null); + } + parent.replace(replacement); } + @Nullable private PsiVariable findPreviousVariable() { - PsiElement scope = variable.getParent(); + PsiElement scope = myVariable.getParent(); while (scope != null) { if (scope instanceof PsiFile || scope instanceof PsiMethod || scope instanceof PsiClassInitializer) break; scope = scope.getParent(); } if (scope == null) return null; - VariablesNotProcessor proc = new VariablesNotProcessor(variable, false); - PsiScopesUtil.treeWalkUp(proc, identifier, scope); - if(proc.size() > 0) - return proc.getResult(0); - return null; + final VariablesNotProcessor proc = new VariablesNotProcessor(myVariable, false); + PsiScopesUtil.treeWalkUp(proc, myIdentifier, scope); + return proc.size() > 0 ? proc.getResult(0) : null; } public boolean startInWriteAction() { return true; } - } diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java index f8de3b44ae76..8e792448c65f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java @@ -117,6 +117,11 @@ public class JavadocTypedHandler extends TypedHandlerDelegate { return null; } return text.subSequence(i + 1, endOffset).toString(); + + // There is a possible case that opening tag has attributes, e.g. [offset]. We want to extract + // only tag name then. + case ' ': + case '\t': endOffset = i; } } return null; diff --git a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java index 4e2a522d17d1..b930439cecfd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -221,6 +221,11 @@ public class JavaDocInfoGenerator { else if (myElement instanceof PsiVariable) { generateVariableJavaDoc(buffer, (PsiVariable)myElement); } + else if (myElement instanceof PsiDirectory) { + final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage((PsiDirectory)myElement); + if (aPackage == null) return null; + generatePackageJavaDoc(buffer, aPackage); + } else if (myElement instanceof PsiPackage) { generatePackageJavaDoc(buffer, (PsiPackage) myElement); } else { diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java index 2bf42fcb0e3d..ff9c2f13df50 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java @@ -2,10 +2,11 @@ package com.intellij.codeInsight.lookup; import com.intellij.codeInsight.AutoPopupController; import com.intellij.codeInsight.TailType; +import com.intellij.codeInsight.completion.CodeCompletionFeatures; import com.intellij.codeInsight.completion.InsertionContext; -import com.intellij.psi.PsiSubstitutor; -import com.intellij.psi.PsiType; -import com.intellij.psi.PsiVariable; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; /** @@ -34,17 +35,27 @@ public class VariableLookupItem extends LookupItem implements Typed public void handleInsert(InsertionContext context) { super.handleInsert(context); - if (context.getCompletionChar() == '=') { + final char completionChar = context.getCompletionChar(); + if (completionChar == '=') { context.setAddCompletionChar(false); TailType.EQ.processTail(context.getEditor(), context.getTailOffset()); } - else if (context.getCompletionChar() == ',' && getAttribute(LookupItem.TAIL_TYPE_ATTR) != TailType.UNKNOWN) { + else if (completionChar == ',' && getAttribute(LookupItem.TAIL_TYPE_ATTR) != TailType.UNKNOWN) { context.setAddCompletionChar(false); TailType.COMMA.processTail(context.getEditor(), context.getTailOffset()); } - else if (context.getCompletionChar() == '.') { + else if (completionChar == '.') { AutoPopupController.getInstance(context.getProject()).autoPopupMemberLookup(context.getEditor(), null); } + else if (completionChar == '!' && PsiType.BOOLEAN.isAssignableFrom(getObject().getType())) { + context.setAddCompletionChar(false); + final PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getTailOffset() - 1, PsiReferenceExpression.class, false); + if (ref != null) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EXCLAMATION_FINISH); + context.getDocument().insertString(ref.getTextRange().getStartOffset(), "!"); + } + } + } } diff --git a/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java b/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java index afd8c91f32b5..6cf445dd6a69 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java @@ -15,12 +15,14 @@ */ package com.intellij.codeInspection; +import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.openapi.project.Project; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.TypeConversionUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -65,15 +67,39 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaLocalInspectionT @Override public void visitNewExpression(PsiNewExpression expression) { if (PsiUtil.getLanguageLevel(expression).isAtLeast(LanguageLevel.JDK_1_7)) { - final PsiJavaCodeReferenceElement classReference = expression.getClassReference(); + final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); if (classReference != null) { final PsiReferenceParameterList parameterList = classReference.getParameterList(); if (parameterList != null) { final PsiTypeElement[] typeElements = parameterList.getTypeParameterElements(); if (typeElements.length > 0) { if (typeElements.length == 1 && typeElements[0].getType() instanceof PsiDiamondType) return; - holder.registerProblem(parameterList, "Redundant type argument #ref #loc", - ProblemHighlightType.LIKE_UNUSED_SYMBOL, new ReplaceWithDiamondFix()); + final PsiDiamondType.DiamondInferenceResult inferenceResult = PsiDiamondType.resolveInferredTypes(expression); + if (inferenceResult.getErrorMessage() == null) { + final PsiType[] types = inferenceResult.getTypes(); + final PsiType[] typeArguments = parameterList.getTypeArguments(); + if (types.length == typeArguments.length) { + for (int i = 0, typeArgumentsLength = typeArguments.length; i < typeArgumentsLength; i++) { + PsiType typeArgument = typeArguments[i]; + if (types[i] instanceof PsiWildcardType) { + final PsiWildcardType wildcardType = (PsiWildcardType)types[i]; + final PsiType bound = wildcardType.getBound(); + if (bound != null) { + if (wildcardType.isExtends()) { + if (bound.isAssignableFrom(typeArgument)) continue; + } else { + if (typeArgument.isAssignableFrom(bound)) continue; + } + } + } + if (!typeArgument.equals(types[i])) { + return; + } + } + } + holder.registerProblem(parameterList, "Redundant type argument #ref #loc", + ProblemHighlightType.LIKE_UNUSED_SYMBOL, new ReplaceWithDiamondFix()); + } } } } @@ -99,6 +125,7 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaLocalInspectionT public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { final PsiElement psiElement = descriptor.getPsiElement(); if (psiElement instanceof PsiReferenceParameterList) { + if (!CodeInsightUtilBase.prepareFileForWrite(psiElement.getContainingFile())) return; final PsiTypeElement[] parameterElements = ((PsiReferenceParameterList)psiElement).getTypeParameterElements(); psiElement.deleteChildRange(parameterElements[0], parameterElements[parameterElements.length - 1]); } diff --git a/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java b/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java index 138a271602e1..34293268c478 100644 --- a/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java @@ -97,7 +97,7 @@ public class DefUseInspection extends BaseLocalInspectionTool { PsiElement context = info.getContext(); PsiVariable psiVariable = info.getVariable(); - if (context instanceof PsiDeclarationStatement) { + if (context instanceof PsiDeclarationStatement || context instanceof PsiResource) { if (!info.isRead()) { if (!isOnTheFly) { holder.registerProblem(psiVariable.getNameIdentifier(), diff --git a/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java b/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java index 3b4d6ecd6955..3f2dde01087f 100644 --- a/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java +++ b/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java @@ -220,7 +220,10 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett " throws Exception { \n" + " foo.foo().bar(\"arg1\", \n" + " \"arg2\"); \n" + + " new Object() {};" + " } \n" + + " class TestInnerClass {}\n" + + " interface TestInnerInterface {}\n" + "}\n" + "\n" + "enum Breed {\n" + diff --git a/java/java-impl/src/com/intellij/ide/structureView/impl/StructureNodeRenderer.java b/java/java-impl/src/com/intellij/ide/structureView/impl/StructureNodeRenderer.java index 74af60cec239..35cc77e12166 100644 --- a/java/java-impl/src/com/intellij/ide/structureView/impl/StructureNodeRenderer.java +++ b/java/java-impl/src/com/intellij/ide/structureView/impl/StructureNodeRenderer.java @@ -23,6 +23,7 @@ import com.intellij.openapi.roots.ui.util.ModifiableCellAppearance; import com.intellij.openapi.util.Iconable; import com.intellij.psi.*; import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiFormatUtilBase; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; @@ -51,7 +52,8 @@ public class StructureNodeRenderer extends ColoredTreeCellRenderer { ModifiableCellAppearance result; if (psiElement instanceof PsiElement && !((PsiElement)psiElement).isValid()) { result = CompositeAppearance.single(name); - } else { + } + else { PsiClass psiClass = getContainingClass(psiElement); if (isInheritedMember(node, psiClass) && psiClass != null) { CompositeAppearance.DequeEnd ending = new CompositeAppearance().getEnding(); @@ -84,13 +86,13 @@ public class StructureNodeRenderer extends ColoredTreeCellRenderer { } } - public static String getNameOf(PsiElement psiElement) { + private static String getNameOf(PsiElement psiElement) { if (psiElement instanceof PsiMethod) return PsiFormatUtil.formatMethod((PsiMethod)psiElement, PsiSubstitutor.EMPTY, - PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.TYPE_AFTER | - PsiFormatUtil.SHOW_PARAMETERS, - PsiFormatUtil.SHOW_TYPE + PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_TYPE | PsiFormatUtilBase.TYPE_AFTER | + PsiFormatUtilBase.SHOW_PARAMETERS, + PsiFormatUtilBase.SHOW_TYPE ); return psiElement.toString(); } @@ -109,23 +111,17 @@ public class StructureNodeRenderer extends ColoredTreeCellRenderer { return new SimpleTextAttributes(nameAttributes.getStyle() | SimpleTextAttributes.STYLE_STRIKEOUT, nameAttributes.getFgColor()); } - public static boolean isDeprecated(Object psiElement) { - if (psiElement instanceof PsiDocCommentOwner) - return ((PsiDocCommentOwner) psiElement).isDeprecated(); - return false; + private static boolean isDeprecated(Object psiElement) { + return psiElement instanceof PsiDocCommentOwner && ((PsiDocCommentOwner)psiElement).isDeprecated(); } - public static PsiClass getContainingClass(Object element) { + private static PsiClass getContainingClass(Object element) { if (element instanceof PsiMember) return ((PsiMember) element).getContainingClass(); - if (element instanceof PsiClass) { - PsiElement parent = ((PsiClass) element).getParent(); - return (PsiClass) (parent instanceof PsiClass ? parent : null); - } return null; } - public static PsiClass getTreeParentClass(Object value) { + private static PsiClass getTreeParentClass(Object value) { if (!(value instanceof TreeNode)) return null; for (TreeNode treeNode = ((TreeNode) value).getParent(); treeNode != null; treeNode = treeNode.getParent()) { diff --git a/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaClassTreeElement.java b/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaClassTreeElement.java index b97433a98ca3..80951de253bd 100644 --- a/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaClassTreeElement.java +++ b/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaClassTreeElement.java @@ -35,10 +35,8 @@ public class JavaClassTreeElement extends JavaClassTreeElementBase { } private Collection getClassChildren() { - ArrayList array = new ArrayList(); - final PsiClass aClass = getElement(); - if (aClass == null) return array; + if (aClass == null) return Collections.emptyList(); List children = Arrays.asList(aClass.getChildren()); Collection ownChildren = new THashSet(); @@ -47,6 +45,7 @@ public class JavaClassTreeElement extends JavaClassTreeElementBase { ContainerUtil.addAll(ownChildren, aClass.getInnerClasses()); ContainerUtil.addAll(ownChildren, aClass.getInitializers()); Collection inherited = new LinkedHashSet(children); + List array = new ArrayList(inherited.size()); aClass.processDeclarations(new AddAllMembersProcessor(inherited, aClass), ResolveState.initial(), null, aClass); diff --git a/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeElement.java b/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeElement.java index 1a5bb59cf538..98a587a369c2 100644 --- a/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeElement.java +++ b/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeElement.java @@ -26,7 +26,6 @@ import java.util.ArrayList; import java.util.Collection; public class JavaFileTreeElement extends PsiTreeElementBase implements ItemPresentation { - public JavaFileTreeElement(PsiJavaFile file) { super(file); } diff --git a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index 23a23791a1aa..b162024dcd20 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -31,11 +31,12 @@ import org.jetbrains.annotations.Nullable; import static com.intellij.lang.PsiBuilderUtil.expect; import static com.intellij.lang.PsiBuilderUtil.nextTokenType; import static com.intellij.lang.java.parser.JavaParserUtil.*; +import static com.intellij.lang.java.parser.JavaParserUtil.exprType; public class DeclarationParser { public enum Context { - FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE + FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE, RESOURCE_LIST } private static final TokenSet AFTER_END_DECLARATION_SET = TokenSet.create(JavaElementType.FIELD, JavaElementType.METHOD); @@ -222,7 +223,7 @@ public class DeclarationParser { if (tokenType == null) return null; if (tokenType == JavaTokenType.LBRACE) { - if (context == Context.FILE || context == Context.CODE_BLOCK) return null; + if (context == Context.FILE || context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) return null; } else if (tokenType == JavaTokenType.IDENTIFIER || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) { if (context == Context.FILE) return null; @@ -234,7 +235,7 @@ public class DeclarationParser { else if (!ElementType.MODIFIER_BIT_SET.contains(tokenType) && !ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType) && tokenType != JavaTokenType.AT && - (context == Context.CODE_BLOCK || tokenType != JavaTokenType.LT)) { + (context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST || tokenType != JavaTokenType.LT)) { return null; } @@ -278,7 +279,7 @@ public class DeclarationParser { final PsiBuilder.Marker idPos = builder.mark(); type = parseTypeNotNull(builder); if (builder.getTokenType() == JavaTokenType.LPARENTH) { // constructor - if (context == Context.CODE_BLOCK) { + if (context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) { declaration.rollbackTo(); return null; } @@ -301,6 +302,10 @@ public class DeclarationParser { declaration.drop(); return modList; } + else if (context == Context.RESOURCE_LIST) { + declaration.rollbackTo(); + return null; + } final PsiBuilder.Marker codeBlock = StatementParser.parseCodeBlock(builder); assert codeBlock != null : builder.getOriginalText(); @@ -326,7 +331,7 @@ public class DeclarationParser { } if (!expect(builder, JavaTokenType.IDENTIFIER)) { - if (context == Context.CODE_BLOCK && modListInfo.second) { + if ((context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) && modListInfo.second) { declaration.rollbackTo(); return null; } @@ -447,33 +452,33 @@ public class DeclarationParser { @NotNull public static PsiBuilder.Marker parseParameterList(final PsiBuilder builder) { - return parseParameterList(builder, false); + return parseElementList(builder, false); } @NotNull public static PsiBuilder.Marker parseResourceList(final PsiBuilder builder) { - return parseParameterList(builder, true); + return parseElementList(builder, true); } @NotNull - private static PsiBuilder.Marker parseParameterList(final PsiBuilder builder, final boolean resources) { + private static PsiBuilder.Marker parseElementList(final PsiBuilder builder, final boolean resources) { assert builder.getTokenType() == JavaTokenType.LPARENTH : builder.getTokenType(); - final PsiBuilder.Marker paramList = builder.mark(); + final PsiBuilder.Marker elementList = builder.mark(); builder.advanceLexer(); final IElementType delimiter = resources ? JavaTokenType.SEMICOLON : JavaTokenType.COMMA; final String noDelimiterMsg = JavaErrorMessages.message(resources ? "expected.semicolon" : "expected.comma"); - final String noParameterMsg = JavaErrorMessages.message(resources ? "expected.resource" : "expected.parameter"); + final String noElementMsg = JavaErrorMessages.message(resources ? "expected.resource" : "expected.parameter"); PsiBuilder.Marker invalidElements = null; String errorMessage = null; boolean delimiterExpected = false; - int paramCount = 0; + int elementCount = 0; while (true) { final IElementType tokenType = builder.getTokenType(); if (tokenType == null || tokenType == JavaTokenType.RPARENTH || tokenType == JavaTokenType.LBRACE) { - boolean noLastParam = !delimiterExpected && paramCount > 0; - if (noLastParam) { + boolean noLastElement = !delimiterExpected && elementCount > 0; + if (noLastElement) { error(builder, JavaErrorMessages.message("expected.identifier.or.type")); } if (tokenType == JavaTokenType.RPARENTH) { @@ -481,13 +486,13 @@ public class DeclarationParser { invalidElements.error(errorMessage); invalidElements = null; } - else if (resources && paramCount == 0) { + else if (resources && elementCount == 0) { error(builder, JavaErrorMessages.message("expected.resource")); } builder.advanceLexer(); } else { - if (!noLastParam) { + if (!noLastElement) { if (invalidElements != null) { invalidElements.error(errorMessage); } @@ -510,27 +515,27 @@ public class DeclarationParser { } } else { - final PsiBuilder.Marker param = parseParameter(builder, true, false, resources); - if (param != null) { + final PsiBuilder.Marker listElement = resources ? parseResource(builder) : parseParameter(builder, true, false); + if (listElement != null) { delimiterExpected = true; if (invalidElements != null) { - invalidElements.errorBefore(errorMessage, param); + invalidElements.errorBefore(errorMessage, listElement); invalidElements = null; } - paramCount++; + elementCount++; continue; } } if (invalidElements == null) { if (builder.getTokenType() == delimiter) { - error(builder, noParameterMsg); + error(builder, noElementMsg); builder.advanceLexer(); continue; } else { invalidElements = builder.mark(); - errorMessage = delimiterExpected ? noDelimiterMsg : noParameterMsg; + errorMessage = delimiterExpected ? noDelimiterMsg : noElementMsg; } } @@ -545,19 +550,19 @@ public class DeclarationParser { invalidElements.error(errorMessage); } - done(paramList, JavaElementType.PARAMETER_LIST); - return paramList; + done(elementList, resources ? JavaElementType.RESOURCE_LIST : JavaElementType.PARAMETER_LIST); + return elementList; } @Nullable - public static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis, final boolean disjunction, final boolean value) { + public static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis, final boolean disjunctiveType) { final PsiBuilder.Marker param = builder.mark(); final Pair modListInfo = parseModifierList(builder); int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD; if (ellipsis) flags |= ReferenceParser.ELLIPSIS; - if (disjunction) flags |= ReferenceParser.DISJUNCTIONS; + if (disjunctiveType) flags |= ReferenceParser.DISJUNCTIONS; final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, flags); if (typeInfo == null) { @@ -572,23 +577,34 @@ public class DeclarationParser { } if (expect(builder, JavaTokenType.IDENTIFIER)) { - eatBrackets(builder, typeInfo != null && typeInfo.isVarArg || value, JavaErrorMessages.message("expected.rparen")); - if (value) { - if (expectOrError(builder, JavaTokenType.EQ, JavaErrorMessages.message("expected.eq"))) { - if (ExpressionParser.parse(builder) == null) { - error(builder, JavaErrorMessages.message("expected.expression")); - } - } - } + eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen")); + done(param, JavaElementType.PARAMETER); + return param; } else { error(builder, JavaErrorMessages.message("expected.identifier")); param.drop(); return modListInfo.first; } + } - done(param, JavaElementType.PARAMETER); - return param; + @Nullable + public static PsiBuilder.Marker parseResource(final PsiBuilder builder) { + PsiBuilder.Marker element = parse(builder, Context.RESOURCE_LIST); + if (exprType(element) == JavaElementType.MODIFIER_LIST) { + return element; + } + else if (element == null) { + element = ExpressionParser.parse(builder); + } + + if (element != null) { + final PsiBuilder.Marker resource = element.precede(); + done(resource, JavaElementType.RESOURCE); + return resource; + } + + return null; } @Nullable @@ -598,7 +614,7 @@ public class DeclarationParser { if (context == Context.CLASS || context == Context.ANNOTATION_INTERFACE) { varType = JavaElementType.FIELD; } - else if (context == Context.CODE_BLOCK) { + else if (context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) { varType = JavaElementType.LOCAL_VARIABLE; } else { @@ -629,6 +645,11 @@ public class DeclarationParser { unclosed = true; break; } + if (context == Context.RESOURCE_LIST) break; + } + else if (context == Context.RESOURCE_LIST) { + error(builder, JavaErrorMessages.message("expected.eq")); + break; } if (builder.getTokenType() != JavaTokenType.COMMA) break; @@ -647,26 +668,28 @@ public class DeclarationParser { builder.advanceLexer(); } - if (builder.getTokenType() == JavaTokenType.SEMICOLON && eatSemicolon) { - builder.advanceLexer(); - } - else { - // special treatment (see DeclarationParserTest.testMultiLineUnclosed()) - if (!builder.eof() && shouldRollback) { - final CharSequence text = builder.getOriginalText(); - final int spaceEnd = builder.getCurrentOffset(); - final int spaceStart = CharArrayUtil.shiftBackward(text, spaceEnd-1, WHITESPACES); - final int lineStart = CharArrayUtil.shiftBackwardUntil(text, spaceEnd, LINE_ENDS); - - if (declarationStart < lineStart && lineStart < spaceStart) { - final int newBufferEnd = CharArrayUtil.shiftForward(text, lineStart, WHITESPACES); - declaration.rollbackTo(); - return parse(stoppingBuilder(builder, newBufferEnd), context); - } + if (context != Context.RESOURCE_LIST) { + if (builder.getTokenType() == JavaTokenType.SEMICOLON && eatSemicolon) { + builder.advanceLexer(); } + else { + // special treatment (see DeclarationParserTest.testMultiLineUnclosed()) + if (!builder.eof() && shouldRollback) { + final CharSequence text = builder.getOriginalText(); + final int spaceEnd = builder.getCurrentOffset(); + final int spaceStart = CharArrayUtil.shiftBackward(text, spaceEnd-1, WHITESPACES); + final int lineStart = CharArrayUtil.shiftBackwardUntil(text, spaceEnd, LINE_ENDS); - if (!unclosed) { - error(builder, JavaErrorMessages.message("expected.semicolon")); + if (declarationStart < lineStart && lineStart < spaceStart) { + final int newBufferEnd = CharArrayUtil.shiftForward(text, lineStart, WHITESPACES); + declaration.rollbackTo(); + return parse(stoppingBuilder(builder, newBufferEnd), context); + } + } + + if (!unclosed) { + error(builder, JavaErrorMessages.message("expected.semicolon")); + } } } diff --git a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java index eb10691aca69..2f4061c26114 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java @@ -375,7 +375,7 @@ public class StatementParser { } final PsiBuilder.Marker afterParenth = builder.mark(); - final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, false, false); + final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, false); if (param == null || JavaParserUtil.exprType(param) != JavaElementType.PARAMETER || builder.getTokenType() != JavaTokenType.COLON) { afterParenth.rollbackTo(); return parseForLoopFromInitialization(builder, statement); @@ -657,7 +657,7 @@ public class StatementParser { return false; } - final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, areMultiCatchSupported(builder), false); + final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, areMultiCatchSupported(builder)); if (param == null) { error(builder, JavaErrorMessages.message("expected.parameter")); } diff --git a/java/java-impl/src/com/intellij/pom/java/impl/PomJavaAspectImpl.java b/java/java-impl/src/com/intellij/pom/java/impl/PomJavaAspectImpl.java index 9d128cb0c178..e3d0276469e1 100644 --- a/java/java-impl/src/com/intellij/pom/java/impl/PomJavaAspectImpl.java +++ b/java/java-impl/src/com/intellij/pom/java/impl/PomJavaAspectImpl.java @@ -68,7 +68,7 @@ public class PomJavaAspectImpl extends PomJavaAspect implements ProjectComponent if(changeSet == null) return; final PsiFile containingFile = changeSet.getRootElement().getPsi().getContainingFile(); if(!(containingFile.getLanguage() instanceof JavaLanguage)) return; - final PomJavaAspectChangeSet set = new PomJavaAspectChangeSet(myPomModel, containingFile); + final PomJavaAspectChangeSet set = new PomJavaAspectChangeSet(myPomModel); set.addChange(new JavaTreeChanged(containingFile)); event.registerChangeSet(this, set); } diff --git a/java/java-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java b/java/java-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java index 59c3cf484641..a7e726fae882 100644 --- a/java/java-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java +++ b/java/java-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java @@ -268,7 +268,6 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor { } } - // generate jump to the top finally block if (!myFinallyBlocks.isEmpty()) { final PsiElement finallyBlock = myFinallyBlocks.peek(); @@ -278,13 +277,10 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor { addElementOffsetLater(finallyBlock, true); } } - } private void generateCheckedExceptionJumps(PsiElement element) { //generate jumps to all handled exception handlers - //if (myCatchBlocks.size() != 0) { - //} Collection unhandledExceptions = ExceptionUtil.collectUnhandledExceptions(element, element.getParent()); for (PsiClassType unhandledException : unhandledExceptions) { ProgressManager.checkCanceled(); @@ -478,7 +474,8 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor { finishElement(statement); } - @Override public void visitDeclarationStatement(PsiDeclarationStatement statement) { + @Override + public void visitDeclarationStatement(PsiDeclarationStatement statement) { startElement(statement); int pc = myCurrentFlow.getSize(); PsiElement[] elements = statement.getDeclaredElements(); @@ -488,28 +485,7 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor { element.accept(this); } else if (element instanceof PsiVariable) { - PsiExpression initializer = ((PsiVariable)element).getInitializer(); - if (initializer != null) { - myStartStatementStack.pushStatement(initializer, false); - myEndStatementStack.pushStatement(initializer, false); - initializer.accept(this); - myStartStatementStack.popStatement(); - myEndStatementStack.popStatement(); - } - if (element instanceof PsiLocalVariable && initializer != null - || element instanceof PsiField) { - if (element instanceof PsiLocalVariable && !myPolicy.isLocalVariableAccepted((PsiLocalVariable)element)) continue; - - if (myAssignmentTargetsAreElements) { - startElement(element); - } - - generateWriteInstruction((PsiVariable)element); - - if (myAssignmentTargetsAreElements) { - finishElement(element); - } - } + processVariable((PsiVariable)element); } } if (pc == myCurrentFlow.getSize()) { @@ -519,6 +495,31 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor { finishElement(statement); } + private void processVariable(final PsiVariable element) { + final PsiExpression initializer = element.getInitializer(); + if (initializer != null) { + myStartStatementStack.pushStatement(initializer, false); + myEndStatementStack.pushStatement(initializer, false); + initializer.accept(this); + myStartStatementStack.popStatement(); + myEndStatementStack.popStatement(); + } + if (element instanceof PsiLocalVariable && initializer != null || + element instanceof PsiField) { + if (element instanceof PsiLocalVariable && !myPolicy.isLocalVariableAccepted((PsiLocalVariable)element)) return; + + if (myAssignmentTargetsAreElements) { + startElement(element); + } + + generateWriteInstruction(element); + + if (myAssignmentTargetsAreElements) { + finishElement(element); + } + } + } + @Override public void visitDoWhileStatement(PsiDoWhileStatement statement) { startElement(statement); myStartStatementStack.pushStatement(statement.getBody() == null ? statement : statement.getBody(), true); @@ -1034,6 +1035,11 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor { myFinallyBlocks.push(finallyBlock); } + PsiResourceList resourceList = statement.getResourceList(); + if (resourceList != null) { + generateCheckedExceptionJumps(resourceList); + resourceList.accept(this); + } PsiCodeBlock tryBlock = statement.getTryBlock(); if (tryBlock != null) { // javac works as if all checked exceptions can occur at the top of the block @@ -1156,8 +1162,36 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor { finishElement(statement); } + @Override + public void visitResourceList(final PsiResourceList resourceList) { + startElement(resourceList); - @Override public void visitWhileStatement(PsiWhileStatement statement) { + final List resources = resourceList.getResources(); + for (PsiResource resource : resources) { + ProgressManager.checkCanceled(); + resource.accept(this); + } + + finishElement(resourceList); + } + + @Override + public void visitResource(final PsiResource resource) { + startElement(resource); + + final PsiElement resourceElement = resource.getResourceElement(); + if (resourceElement instanceof PsiLocalVariable) { + processVariable((PsiLocalVariable)resourceElement); + } + else if (resourceElement instanceof PsiExpression) { + resourceElement.accept(this); + } + + finishElement(resource); + } + + @Override + public void visitWhileStatement(PsiWhileStatement statement) { startElement(statement); if (statement.getBody() == null) { myStartStatementStack.pushStatement(statement, false); diff --git a/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java b/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java index fb0190f78c80..daba17413a5d 100644 --- a/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java +++ b/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java @@ -13,15 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Mar 22, 2002 - * Time: 7:25:02 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ package com.intellij.psi.controlFlow; import com.intellij.openapi.diagnostic.Logger; @@ -34,16 +25,20 @@ import com.intellij.util.containers.IntArrayList; import com.intellij.util.containers.Queue; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Set; +/** + * @author max + * Date: Mar 22, 2002 + */ public class DefUseUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.defUse.DefUseUtil"); - private DefUseUtil() { - } + private DefUseUtil() { } public static class Info { private final PsiVariable myVariable; @@ -132,6 +127,7 @@ public class DefUseUtil { } } + @Nullable public static List getUnusedDefs(PsiCodeBlock body, Set outUsedVariables) { if (body == null) { return null; @@ -232,12 +228,13 @@ public class DefUseUtil { if (instruction instanceof WriteVariableInstruction) { WriteVariableInstruction writeInstruction = (WriteVariableInstruction)instruction; if (!defsArmed[i]) { - PsiElement context = flow.getElement(i); - context = PsiTreeUtil.getNonStrictParentOfType(context, PsiStatement.class, PsiAssignmentExpression.class, - PsiPostfixExpression.class, PsiPrefixExpression.class); + PsiElement context = PsiTreeUtil.getNonStrictParentOfType(flow.getElement(i), + PsiStatement.class, PsiAssignmentExpression.class, + PsiPostfixExpression.class, PsiPrefixExpression.class, + PsiResource.class); PsiVariable psiVariable = writeInstruction.variable; if (context != null && !(context instanceof PsiTryStatement)) { - if (context instanceof PsiDeclarationStatement && psiVariable.getInitializer() == null) { + if (isDeclaration(context) && psiVariable.getInitializer() == null) { if (!assignedVariables.contains(psiVariable)) { unusedDefs.add(new Info(psiVariable, context, false)); } @@ -251,7 +248,11 @@ public class DefUseUtil { } return unusedDefs; + } + private static boolean isDeclaration(final PsiElement context) { + return context instanceof PsiDeclarationStatement || + context instanceof PsiResource && ((PsiResource)context).getResourceElement() instanceof PsiLocalVariable; } @NotNull @@ -476,5 +477,4 @@ public class DefUseUtil { return true; } }; - } diff --git a/java/java-impl/src/com/intellij/psi/filters/element/ExcludeSillyAssignment.java b/java/java-impl/src/com/intellij/psi/filters/element/ExcludeSillyAssignment.java index a5bb70e4e01b..e999d77684ad 100644 --- a/java/java-impl/src/com/intellij/psi/filters/element/ExcludeSillyAssignment.java +++ b/java/java-impl/src/com/intellij/psi/filters/element/ExcludeSillyAssignment.java @@ -39,7 +39,12 @@ public class ExcludeSillyAssignment implements ElementFilter { final PsiExpression left = ((PsiAssignmentExpression)each).getLExpression(); if (left instanceof PsiReferenceExpression) { final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)left; - if (referenceExpression.isQualified()) return true; + final PsiElement qualifier = referenceExpression.getQualifier(); + if (qualifier != null) { + if (!(qualifier instanceof PsiThisExpression) || ((PsiThisExpression)qualifier).getQualifier() != null) { + return true; + } + } return !referenceExpression.isReferenceTo((PsiElement)element); } diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/ClassLiteralGetter.java b/java/java-impl/src/com/intellij/psi/filters/getters/ClassLiteralGetter.java index 747f64254254..8876359ea21b 100644 --- a/java/java-impl/src/com/intellij/psi/filters/getters/ClassLiteralGetter.java +++ b/java/java-impl/src/com/intellij/psi/filters/getters/ClassLiteralGetter.java @@ -16,30 +16,26 @@ package com.intellij.psi.filters.getters; import com.intellij.codeInsight.CodeInsightUtil; -import com.intellij.codeInsight.completion.CompletionProvider; -import com.intellij.codeInsight.completion.CompletionResultSet; import com.intellij.codeInsight.completion.JavaSmartCompletionParameters; import com.intellij.codeInsight.completion.PrefixMatcher; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; +import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class ClassLiteralGetter extends CompletionProvider { +public class ClassLiteralGetter { private static final Logger LOG = Logger.getInstance("com.intellij.psi.filters.getters.ClassLiteralGetter"); - @Override - protected void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, - ProcessingContext context, - @NotNull CompletionResultSet result) { + public static void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, + @NotNull Consumer result, final PrefixMatcher matcher) { - final PrefixMatcher matcher = result.getPrefixMatcher(); final Condition shortNameCondition = new Condition() { public boolean value(String s) { return matcher.prefixMatches(s); @@ -61,7 +57,7 @@ public class ClassLiteralGetter extends CompletionProvider shortNameCondition, final PsiType classParameter, - CompletionResultSet result) { + Consumer result, PrefixMatcher matcher) { final String canonicalText = classParameter.getCanonicalText(); - if (CommonClassNames.JAVA_LANG_OBJECT.equals(canonicalText) && StringUtil.isEmpty(result.getPrefixMatcher().getPrefix())) { + if (CommonClassNames.JAVA_LANG_OBJECT.equals(canonicalText) && StringUtil.isEmpty(matcher.getPrefix())) { return; } @@ -80,13 +76,13 @@ public class ClassLiteralGetter extends CompletionProvider resultSet, final PsiFile context) { if (type instanceof PsiClassType && PsiUtil.resolveClassInType(type) != null && !((PsiClassType)type).hasParameters() && !(((PsiClassType)type).resolve() instanceof PsiTypeParameter)) { try { - resultSet.addElement(AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(new ClassLiteralLookupElement((PsiClassType)type, context))); + resultSet.consume(AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(new ClassLiteralLookupElement((PsiClassType)type, context))); } catch (IncorrectOperationException e) { LOG.error(e); diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java b/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java index 1ca922007a95..fc0b4d1ac854 100644 --- a/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java +++ b/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java @@ -15,10 +15,9 @@ */ package com.intellij.psi.filters.getters; -import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.completion.JavaMethodCallElement; import com.intellij.codeInsight.completion.SmartCompletionDecorator; -import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.lookup.*; import com.intellij.psi.*; import com.intellij.psi.filters.TrueFilter; @@ -27,6 +26,7 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.Consumer; import org.jetbrains.annotations.Nullable; /** @@ -38,7 +38,7 @@ import org.jetbrains.annotations.Nullable; */ public class MembersGetter { - public static void addMembers(PsiElement position, PsiType expectedType, CompletionResultSet results) { + public static void addMembers(PsiElement position, PsiType expectedType, Consumer results) { final PsiClass psiClass = PsiUtil.resolveClassInType(expectedType); processMembers(position, results, psiClass, PsiTreeUtil.getParentOfType(position, PsiAnnotation.class) != null, expectedType); @@ -47,7 +47,7 @@ public class MembersGetter { } } - private static void addConstantsFromTargetClass(PsiElement position, PsiType expectedType, CompletionResultSet results) { + private static void addConstantsFromTargetClass(PsiElement position, PsiType expectedType, Consumer results) { PsiElement parent = position.getParent(); if (!(parent instanceof PsiReferenceExpression)) { return; @@ -99,7 +99,7 @@ public class MembersGetter { return null; } - private static void processMembers(final PsiElement context, final CompletionResultSet results, @Nullable final PsiClass where, + private static void processMembers(final PsiElement context, final Consumer results, @Nullable final PsiClass where, final boolean acceptMethods, PsiType expectedType) { if (where == null) return; @@ -132,7 +132,7 @@ public class MembersGetter { } final PsiType itemType = ((TypedLookupItem)item).getType(); if (itemType != null && expectedType.isAssignableFrom(itemType)) { - results.addElement(item); + results.consume(item); } } } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java index 5ab5d59e7187..2e1bad933cc9 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java @@ -213,6 +213,10 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { if (aClass.isEnum()) { createParenSpace(true, false); } + else if (myRole2 == ChildRole.RBRACE && mySettings.KEEP_SIMPLE_CLASSES_IN_ONE_LINE) { + int spaces = mySettings.SPACE_WITHIN_BRACES ? 1 : 0; + myResult = Spacing.createSpacing(spaces, spaces, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS); + } else if (aClass instanceof PsiAnonymousClass) { if (myRole2 == ChildRole.CLASS_INITIALIZER && isTheOnlyClassMember(myChild2)) { myResult = Spacing.createSpacing(0, 0, 0, diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-impl/src/com/intellij/psi/impl/PsiImplUtil.java index c2a7fa637c26..44bbf950c6d1 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -185,35 +185,30 @@ public class PsiImplUtil { if (list != null && !list.processDeclarations(processor, state, null, place)) return false; } if (lastParent instanceof PsiCodeBlock) { - final PsiParameterList parameterList = method.getParameterList(); - if (processDeclarationsInParameterList(parameterList, processor, state)) return false; + final PsiParameter[] parameters = method.getParameterList().getParameters(); + for (PsiParameter parameter : parameters) { + if (!processor.execute(parameter, state)) return false; + } } return true; } - public static boolean processDeclarationsInTryStatement(@NotNull final PsiTryStatement statement, + public static boolean processDeclarationsInResourceList(@NotNull final PsiResourceList resourceList, @NotNull final PsiScopeProcessor processor, @NotNull final ResolveState state, final PsiElement lastParent) { - if (lastParent instanceof PsiCodeBlock) { - final PsiParameterList parameterList = statement.getResourceList(); - if (parameterList != null && processDeclarationsInParameterList(parameterList, processor, state)) return false; + final List resources = resourceList.getResources(); + for (PsiResource resource : resources) { + final PsiElement resourceElement = resource.getResourceElement(); + if (resourceElement instanceof PsiLocalVariable && + !resourceElement.equals(lastParent) && + !processor.execute(resourceElement, state)) return false; } return true; } - private static boolean processDeclarationsInParameterList(@NotNull final PsiParameterList parameterList, - @NotNull final PsiScopeProcessor processor, - @NotNull final ResolveState state) { - final PsiParameter[] parameters = parameterList.getParameters(); - for (PsiParameter parameter : parameters) { - if (!processor.execute(parameter, state)) return true; - } - return false; - } - public static boolean hasTypeParameters(@NotNull PsiTypeParameterListOwner owner) { final PsiTypeParameterList typeParameterList = owner.getTypeParameterList(); return typeParameterList != null && typeParameterList.getTypeParameters().length != 0; @@ -233,7 +228,7 @@ public class PsiImplUtil { types[i] = typeElements[i].getType(); } if (types.length == 1 && types[0] instanceof PsiDiamondType) { - return ((PsiDiamondType)types[0]).getInferredTypes(); + return ((PsiDiamondType)types[0]).resolveInferredTypes().getTypes(); } return types; } diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java index 083602d0e83f..49ec4a074d84 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java @@ -60,14 +60,14 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ private static final JavaParserUtil.ParserWrapper PARAMETER = new JavaParserUtil.ParserWrapper() { @Override public void parse(final PsiBuilder builder) { - DeclarationParser.parseParameter(builder, true, false, false); + DeclarationParser.parseParameter(builder, true, false); } }; private static final JavaParserUtil.ParserWrapper RESOURCE = new JavaParserUtil.ParserWrapper() { @Override public void parse(final PsiBuilder builder) { - DeclarationParser.parseParameter(builder, true, false, true); + DeclarationParser.parseResource(builder); } }; @@ -169,6 +169,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiAnnotation createAnnotationFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, ANNOTATION, false), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); @@ -179,16 +180,19 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiDocTag createDocTagFromText(@NotNull final String text) throws IncorrectOperationException { return createDocCommentFromText(join("/**\n", text, "\n */")).getTags()[0]; } @NotNull + @Override public PsiDocTag createDocTagFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { return createDocTagFromText(text); } @NotNull + @Override public PsiDocComment createDocCommentFromText(@NotNull final String text) throws IncorrectOperationException { final PsiMethod method = createMethodFromText(join(text, "void m();"), null); final PsiDocComment comment = method.getDocComment(); @@ -197,11 +201,13 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiDocComment createDocCommentFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { return createDocCommentFromText(text); } @NotNull + @Override public PsiClass createClassFromText(@NotNull final String body, final PsiElement context) throws IncorrectOperationException { final PsiJavaFile aFile = createDummyJavaFile(join("class _Dummy_ { ", body, " }")); final PsiClass[] classes = aFile.getClasses(); @@ -212,6 +218,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiField createFieldFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, DECLARATION, false), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); @@ -222,6 +229,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiMethod createMethodFromText(@NotNull final String text, final PsiElement context, final LanguageLevel level) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, DECLARATION, false, level), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); @@ -232,17 +240,16 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public final PsiMethod createMethodFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final LanguageLevel level = LanguageLevelProjectExtension.getInstance(myManager.getProject()).getLanguageLevel(); return createMethodFromText(text, context, level); } @NotNull + @Override public PsiParameter createParameterFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { - final boolean resource = context instanceof PsiParameterList && - context.getParent() instanceof PsiTryStatement; - final JavaParserUtil.ParserWrapper wrapper = resource ? RESOURCE : PARAMETER; - final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, wrapper, false), context); + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, PARAMETER, false), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiParameter)) { throw new IncorrectOperationException("Incorrect parameter \"" + text + "\"."); @@ -251,11 +258,24 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override + public PsiResource createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, RESOURCE, false), context); + final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); + if (!(element instanceof PsiResource)) { + throw new IncorrectOperationException("Incorrect resource \"" + text + "\"."); + } + return (PsiResource)element; + } + + @NotNull + @Override public PsiType createTypeFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { return createTypeInner(text, context, false); } @NotNull + @Override public PsiTypeElement createTypeElementFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final boolean multiCatch = context instanceof PsiParameter && context.getParent() instanceof PsiCatchSection && @@ -281,6 +301,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiJavaCodeReferenceElement createReferenceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final boolean isStaticImport = context instanceof PsiImportStaticStatement && !((PsiImportStaticStatement)context).isOnDemand(); @@ -294,6 +315,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiCodeBlock createCodeBlockFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, CODE_BLOCK, true), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); @@ -304,6 +326,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiStatement createStatementFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, STATEMENT, false), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); @@ -314,6 +337,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiExpression createExpressionFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, EXPRESSION, false), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); @@ -330,6 +354,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiTypeParameter createTypeParameterFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, TYPE_PARAMETER, false), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); @@ -340,6 +365,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiComment createCommentFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final PsiJavaFile aFile = createDummyJavaFile(text); for (PsiElement aChildren : aFile.getChildren()) { @@ -357,6 +383,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiEnumConstant createEnumConstantFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, ENUM_CONSTANT, false), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); @@ -367,6 +394,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ } @NotNull + @Override public PsiCatchSection createCatchSection(@NotNull final PsiClassType exceptionType, @NotNull final String exceptionName, final PsiElement context) throws IncorrectOperationException { final String text = join("catch (", exceptionType.getCanonicalText(), " ", exceptionName, ") {}"); @@ -406,6 +434,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ psiCatchSection.getCatchBlock().replace(codeBlockFromText); } + @Override public PsiType createPrimitiveType(@NotNull final String text, @NotNull final PsiAnnotation[] annotations) throws IncorrectOperationException { final PsiPrimitiveType primitiveType = getPrimitiveType(text); if (primitiveType == null) { diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java b/java/java-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java index 14527352e906..c6c975bb5653 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java @@ -177,7 +177,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { final List substituted = ContainerUtil.map(disjunctionType.getDisjunctions(), new Function() { @Override public PsiType fun(PsiType psiType) { return psiType.accept(SubstitutionVisitorBase.this); } }); - return new PsiDisjunctionType(substituted, disjunctionType.getManager()); + return disjunctionType.newDisjunctionType(substituted); } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java index 130fadd9649a..465ba6e29c9f 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java @@ -755,7 +755,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme } else { while (superParent != null) { - if (superParent instanceof PsiCodeBlock || superParent instanceof PsiVariable) { + if (superParent instanceof PsiCodeBlock || superParent instanceof PsiLocalVariable) { smartCompletion = false; break; } @@ -763,8 +763,6 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme } } if (!smartCompletion && !isCodeFragmentType(getTreeParent().getElementType()) && !(getParent() instanceof PsiAnnotation)) { - /*filter.addFilter(ElementClassFilter.CLASS); - filter.addFilter(ElementClassFilter.PACKAGE);*/ filter.addFilter(new AndFilter(ElementClassFilter.METHOD, new NotFilter(new ConstructorFilter()))); filter.addFilter(ElementClassFilter.VARIABLE); } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java index fe99c2b043bf..e2329c6d3578 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java @@ -82,7 +82,7 @@ public class PsiModifierListImpl extends JavaStubPsiElement super(node); } - public boolean hasModifierProperty(@NotNull String name){ + public boolean hasModifierProperty(@NotNull String name) { final PsiModifierListStub stub = getStub(); if (stub != null) { int flag = NAME_TO_MODIFIER_FLAG_MAP.get(name); @@ -93,34 +93,34 @@ public class PsiModifierListImpl extends JavaStubPsiElement IElementType type = NAME_TO_KEYWORD_TYPE_MAP.get(name); PsiElement parent = getParent(); - if (parent instanceof PsiClass){ - PsiElement pparent = parent.getParent(); - if (pparent instanceof PsiClass && ((PsiClass)pparent).isInterface()){ - if (type == JavaTokenType.PUBLIC_KEYWORD){ + if (parent instanceof PsiClass) { + PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiClass && ((PsiClass)grandParent).isInterface()) { + if (type == JavaTokenType.PUBLIC_KEYWORD) { return true; } - if (type == null){ // package local + if (type == null) { // package local return false; } - if (type == JavaTokenType.STATIC_KEYWORD){ + if (type == JavaTokenType.STATIC_KEYWORD) { return true; } } - if (((PsiClass)parent).isInterface()){ - if (type == JavaTokenType.ABSTRACT_KEYWORD){ + if (((PsiClass)parent).isInterface()) { + if (type == JavaTokenType.ABSTRACT_KEYWORD) { return true; } // nested interface is implicitly static - if (pparent instanceof PsiClass) { - if (type == JavaTokenType.STATIC_KEYWORD){ + if (grandParent instanceof PsiClass) { + if (type == JavaTokenType.STATIC_KEYWORD) { return true; } } } - if (((PsiClass)parent).isEnum()){ + if (((PsiClass)parent).isEnum()) { if (type == JavaTokenType.STATIC_KEYWORD) { - if (!(pparent instanceof PsiFile)) return true; + if (!(grandParent instanceof PsiFile)) return true; } else if (type == JavaTokenType.FINAL_KEYWORD) { final PsiField[] fields = ((PsiClass)parent).getFields(); @@ -138,37 +138,37 @@ public class PsiModifierListImpl extends JavaStubPsiElement } } } - else if (parent instanceof PsiMethod){ + else if (parent instanceof PsiMethod) { PsiClass aClass = ((PsiMethod)parent).getContainingClass(); - if (aClass != null && aClass.isInterface()){ - if (type == JavaTokenType.PUBLIC_KEYWORD){ + if (aClass != null && aClass.isInterface()) { + if (type == JavaTokenType.PUBLIC_KEYWORD) { return true; } - if (type == null){ // package local + if (type == null) { // package local return false; } - if (type == JavaTokenType.ABSTRACT_KEYWORD){ + if (type == JavaTokenType.ABSTRACT_KEYWORD) { return true; } } } - else if (parent instanceof PsiField){ + else if (parent instanceof PsiField) { if (parent instanceof PsiEnumConstant) { return type == JavaTokenType.PUBLIC_KEYWORD || type == JavaTokenType.STATIC_KEYWORD || type == JavaTokenType.FINAL_KEYWORD; } else { PsiClass aClass = ((PsiField)parent).getContainingClass(); - if (aClass != null && aClass.isInterface()){ - if (type == JavaTokenType.PUBLIC_KEYWORD){ + if (aClass != null && aClass.isInterface()) { + if (type == JavaTokenType.PUBLIC_KEYWORD) { return true; } - if (type == null){ // package local + if (type == null) { // package local return false; } - if (type == JavaTokenType.STATIC_KEYWORD){ + if (type == JavaTokenType.STATIC_KEYWORD) { return true; } - if (type == JavaTokenType.FINAL_KEYWORD){ + if (type == JavaTokenType.FINAL_KEYWORD) { return true; } } @@ -177,9 +177,15 @@ public class PsiModifierListImpl extends JavaStubPsiElement else if (parent instanceof PsiParameter) { if (type == JavaTokenType.FINAL_KEYWORD && ((PsiParameter)parent).getType() instanceof PsiDisjunctionType) return true; } + else if (parent instanceof PsiLocalVariable) { + PsiElement grandParent = parent.getParent(); + if (type == JavaTokenType.FINAL_KEYWORD && grandParent instanceof PsiResource) return true; + } - if (type == null){ // package local - return !hasModifierProperty(PsiModifier.PUBLIC) && !hasModifierProperty(PsiModifier.PRIVATE) && !hasModifierProperty(PsiModifier.PROTECTED); + if (type == null) { // package local + return !hasModifierProperty(PsiModifier.PUBLIC) && + !hasModifierProperty(PsiModifier.PRIVATE) && + !hasModifierProperty(PsiModifier.PROTECTED); } return getNode().findChildByType(type) != null; diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java index fdcdc3a5ceb9..551b95ac8ba4 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java @@ -403,8 +403,8 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { final boolean forCompletion) { PsiTypeParameterListOwner owner = typeParameter.getOwner(); Pair substitution = null; - if (owner instanceof PsiMethod && parent instanceof PsiMethodCallExpression) { - PsiMethodCallExpression methodCall = (PsiMethodCallExpression)parent; + if (owner instanceof PsiMethod && parent instanceof PsiCallExpression) { + PsiCallExpression methodCall = (PsiCallExpression)parent; substitution = inferMethodTypeParameterFromParent(methodCall.getParent(), methodCall, typeParameter, substitutor, forCompletion); } return substitution; @@ -604,7 +604,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } private static Pair inferMethodTypeParameterFromParent(PsiElement parent, - PsiMethodCallExpression methodCall, + PsiCallExpression methodCall, final PsiTypeParameter typeParameter, PsiSubstitutor substitutor, final boolean forCompletion) { @@ -701,13 +701,13 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return result; } - private static final ThreadLocal> myBlockedForInferenceMethodCalls = new ThreadLocal>() { - protected List initialValue() { - return new ArrayList(2); + private static final ThreadLocal> myBlockedForInferenceMethodCalls = new ThreadLocal>() { + protected List initialValue() { + return new ArrayList(2); } }; - private static Pair inferTypeForCompletionFromCallContext(final PsiMethodCallExpression innerMethodCall, + private static Pair inferTypeForCompletionFromCallContext(final PsiCallExpression innerMethodCall, final PsiExpressionList expressionList, final PsiCallExpression contextCall, final PsiTypeParameter typeParameter) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java index 4270606ec5e1..593bb11d77c3 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java @@ -127,9 +127,11 @@ public interface JavaElementType { IElementType THROW_STATEMENT = new JavaCompositeElementType("THROW_STATEMENT", PsiThrowStatementImpl.class); IElementType SYNCHRONIZED_STATEMENT = new JavaCompositeElementType("SYNCHRONIZED_STATEMENT", PsiSynchronizedStatementImpl.class); IElementType TRY_STATEMENT = new JavaCompositeElementType("TRY_STATEMENT", PsiTryStatementImpl.class); + IElementType RESOURCE_LIST = new JavaCompositeElementType("RESOURCE_LIST", PsiResourceListImpl.class); + IElementType RESOURCE = new JavaCompositeElementType("RESOURCE", PsiResourceImpl.class); + IElementType CATCH_SECTION = new JavaCompositeElementType("CATCH_SECTION", PsiCatchSectionImpl.class); IElementType LABELED_STATEMENT = new JavaCompositeElementType("LABELED_STATEMENT", PsiLabeledStatementImpl.class); IElementType ASSERT_STATEMENT = new JavaCompositeElementType("ASSERT_STATEMENT", PsiAssertStatementImpl.class); - IElementType CATCH_SECTION = new JavaCompositeElementType("CATCH_SECTION", PsiCatchSectionImpl.class); IElementType ANNOTATION_ARRAY_INITIALIZER = new JavaCompositeElementType("ANNOTATION_ARRAY_INITIALIZER", PsiArrayInitializerMemberValueImpl.class); IElementType NAME_VALUE_PAIR = new JavaCompositeElementType("NAME_VALUE_PAIR", PsiNameValuePairImpl.class, true); IElementType ANNOTATION_PARAMETER_LIST = new JavaCompositeElementType("ANNOTATION_PARAMETER_LIST", PsiAnnotationParameterListImpl.class, true); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiLocalVariableImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiLocalVariableImpl.java index 61872ff2f4c2..ad809cdf9ad3 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiLocalVariableImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiLocalVariableImpl.java @@ -49,7 +49,7 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.util.Set; -public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLocalVariable, PsiVariableEx, Constants { +public class PsiLocalVariableImpl extends CompositePsiElement implements PsiScopedLocalVariable, PsiVariableEx, Constants { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiLocalVariableImpl"); private volatile String myCachedName = null; @@ -94,7 +94,7 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLoca @NotNull public PsiTypeElement getTypeElement() { ASTNode first = getTreeParent().findChildByType(LOCAL_VARIABLE); - return (PsiTypeElement)SourceTreeToPsiMap.treeElementToPsi(first.findChildByType(TYPE)); + return SourceTreeToPsiMap.treeToPsiNotNull(first.findChildByType(TYPE)); } public PsiModifierList getModifierList() { @@ -105,7 +105,8 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLoca } public boolean hasModifierProperty(@NotNull String name) { - return getModifierList().hasModifierProperty(name); + final PsiModifierList modifierList = getModifierList(); + return modifierList != null && modifierList.hasModifierProperty(name); } public PsiExpression getInitializer() { @@ -278,6 +279,21 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLoca return "PsiLocalVariable:" + getName(); } + @NotNull + public PsiElement[] getDeclarationScope() { + final PsiElement parentElement = getParent(); + if (parentElement instanceof PsiDeclarationStatement) { + return new PsiElement[]{parentElement.getParent()}; + } + else if (parentElement instanceof PsiResource) { + final PsiResourceList resourceList = (PsiResourceList)parentElement.getParent(); + final PsiTryStatement tryStatement = (PsiTryStatement)resourceList.getParent(); + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + return tryBlock != null ? new PsiElement[]{resourceList, tryBlock} : new PsiElement[]{resourceList}; + } + return new PsiElement[]{parentElement.getParent()}; + } + @NotNull public SearchScope getUseScope() { if (JspPsiUtil.isInJspFile(this)) { @@ -304,9 +320,9 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLoca } } - PsiElement parentElement = getParent(); - if (parentElement instanceof PsiDeclarationStatement) { - return new LocalSearchScope(parentElement.getParent()); + final PsiElement parentElement = getParent(); + if (parentElement instanceof PsiDeclarationStatement || parentElement instanceof PsiResource) { + return new LocalSearchScope(getDeclarationScope()); } else { return getManager().getFileManager().getUseScope(this); @@ -317,6 +333,7 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLoca final RowIcon baseIcon = createLayeredIcon(Icons.VARIABLE_ICON, ElementPresentationUtil.getFlags(this, false)); return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon); } + public PsiType getTypeNoResolve() { return getType(); } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceImpl.java new file mode 100644 index 000000000000..6a09eefdfece --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceImpl.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2011 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.psi.impl.source.tree.java; + +import com.intellij.openapi.diagnostic.LogUtil; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.CompositePsiElement; +import com.intellij.psi.impl.source.tree.JavaElementType; +import org.jetbrains.annotations.NotNull; + +public class PsiResourceImpl extends CompositePsiElement implements PsiResource { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiResourceImpl"); + + public PsiResourceImpl() { + super(JavaElementType.RESOURCE); + } + + @NotNull + @Override + public PsiElement getResourceElement() { + final PsiElement element = getFirstChild(); + assert element != null : this; + return element; + } + + @Override + public PsiType getType() { + final PsiElement element = getResourceElement(); + if (element instanceof PsiLocalVariable) { + return ((PsiLocalVariable)element).getType(); + } + else if (element instanceof PsiExpression) { + return ((PsiExpression)element).getType(); + } + LOG.error("Unexpected resource type: " + LogUtil.objectAndClass(element)); + return null; + } + + @Override + public void accept(@NotNull final PsiElementVisitor visitor) { + if (visitor instanceof JavaElementVisitor) { + ((JavaElementVisitor)visitor).visitResource(this); + } + else { + visitor.visitElement(this); + } + } + + public String getName() { + final PsiElement element = getFirstChild(); + if (element instanceof PsiLocalVariable) return ((PsiLocalVariable)element).getName(); + if (element instanceof PsiAssignmentExpression) return ((PsiAssignmentExpression)element).getLExpression().toString(); + return ""; + } + + @Override + public String toString() { + return "PsiResource:" + getName(); + } +} diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceListImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceListImpl.java new file mode 100644 index 000000000000..0ecec5626043 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceListImpl.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2011 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.psi.impl.source.tree.java; + +import com.intellij.psi.*; +import com.intellij.psi.impl.PsiImplUtil; +import com.intellij.psi.impl.source.tree.CompositePsiElement; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class PsiResourceListImpl extends CompositePsiElement implements PsiResourceList { + public PsiResourceListImpl() { + super(JavaElementType.RESOURCE_LIST); + } + + @NotNull + @Override + public List getResources() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, PsiResource.class); + } + + @Override + public void accept(@NotNull final PsiElementVisitor visitor) { + if (visitor instanceof JavaElementVisitor) { + ((JavaElementVisitor)visitor).visitResourceList(this); + } + else { + visitor.visitElement(this); + } + } + + @Override + public boolean processDeclarations(@NotNull final PsiScopeProcessor processor, + @NotNull final ResolveState state, + final PsiElement lastParent, + @NotNull final PsiElement place) { + return PsiImplUtil.processDeclarationsInResourceList(this, processor, state, lastParent); + } + + @Override + public String toString() { + return "PsiResourceList:" + getText(); + } +} diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiTryStatementImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiTryStatementImpl.java index dc23a38cd074..3abdb2b2bb23 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiTryStatementImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiTryStatementImpl.java @@ -93,8 +93,8 @@ public class PsiTryStatementImpl extends CompositePsiElement implements PsiTrySt } @Override - public PsiParameterList getResourceList() { - return PsiTreeUtil.findChildOfType(this, PsiParameterList.class); + public PsiResourceList getResourceList() { + return PsiTreeUtil.findChildOfType(this, PsiResourceList.class); } public ASTNode findChildByRole(int role) { @@ -164,7 +164,12 @@ public class PsiTryStatementImpl extends CompositePsiElement implements PsiTrySt @NotNull final ResolveState state, final PsiElement lastParent, @NotNull final PsiElement place) { - return PsiImplUtil.processDeclarationsInTryStatement(this, processor, state, lastParent); + final PsiResourceList resourceList = getResourceList(); + if (resourceList != null && lastParent instanceof PsiCodeBlock && lastParent == getTryBlock()) { + return PsiImplUtil.processDeclarationsInResourceList(resourceList, processor, state, lastParent); + } + + return true; } public String toString() { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java index 991546fcdc77..f1162d909db6 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java @@ -26,11 +26,13 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; @@ -131,6 +133,11 @@ class VariableInplaceIntroducer extends VariableInplaceRenamer { return super.createLookupItems(lookupItems, name); } + @Override + protected TextRange preserveSelectedRange(SelectionModel selectionModel) { + return null; + } + @Override protected void moveOffsetAfter(boolean success) { try { diff --git a/java/java-impl/testSrc/com/intellij/codeInsight/editorActions/JavadocTypedHandlerTest.java b/java/java-impl/testSrc/com/intellij/codeInsight/editorActions/JavadocTypedHandlerTest.java index 891157c1bdaa..b5935250a698 100644 --- a/java/java-impl/testSrc/com/intellij/codeInsight/editorActions/JavadocTypedHandlerTest.java +++ b/java/java-impl/testSrc/com/intellij/codeInsight/editorActions/JavadocTypedHandlerTest.java @@ -37,6 +37,12 @@ public class JavadocTypedHandlerTest { doTest("", null); } + @Test + public void tagWithAttribute() { + doTest("", "a"); + //TODO den implement + } + private static void doTest(String text, String expected) { StringBuilder normalized = new StringBuilder(); int offset = text.indexOf(CARET_MARKER); diff --git a/java/java-tests/testData/codeInsight/completion/normal/AssigningFieldForTheFirstTime.java b/java/java-tests/testData/codeInsight/completion/normal/AssigningFieldForTheFirstTime.java new file mode 100644 index 000000000000..b8530645f6ca --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/AssigningFieldForTheFirstTime.java @@ -0,0 +1,6 @@ +class A { + final boolean aboo; + A() { + abo + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/AssigningFieldForTheFirstTime_after.java b/java/java-tests/testData/codeInsight/completion/normal/AssigningFieldForTheFirstTime_after.java new file mode 100644 index 000000000000..b355e702cafb --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/AssigningFieldForTheFirstTime_after.java @@ -0,0 +1,6 @@ +class A { + final boolean aboo; + A() { + aboo + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/DefaultInSwitch.java b/java/java-tests/testData/codeInsight/completion/normal/DefaultInSwitch.java new file mode 100644 index 000000000000..8bfb38e08d3a --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/DefaultInSwitch.java @@ -0,0 +1,9 @@ +public class ConstConfig { + { + switch (a) { + case Foooo: {} + def + + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/DefaultInSwitch_after.java b/java/java-tests/testData/codeInsight/completion/normal/DefaultInSwitch_after.java new file mode 100644 index 000000000000..bbd0330ecd94 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/DefaultInSwitch_after.java @@ -0,0 +1,9 @@ +public class ConstConfig { + { + switch (a) { + case Foooo: {} + default: + + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/FieldNegation.java b/java/java-tests/testData/codeInsight/completion/normal/FieldNegation.java new file mode 100644 index 000000000000..7379f0135de7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/FieldNegation.java @@ -0,0 +1,7 @@ +public class ConstConfig { + public static boolean testMode = false; + + { + if (testx) + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/FieldNegation_after.java b/java/java-tests/testData/codeInsight/completion/normal/FieldNegation_after.java new file mode 100644 index 000000000000..39e4af0ac513 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/FieldNegation_after.java @@ -0,0 +1,7 @@ +public class ConstConfig { + public static boolean testMode = false; + + { + if (!testModex) + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/FieldType.java b/java/java-tests/testData/codeInsight/completion/normal/FieldType.java new file mode 100644 index 000000000000..a2abc3425058 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/FieldType.java @@ -0,0 +1,4 @@ +class A { + private lo localizedStringManager; + +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/FieldType_after.java b/java/java-tests/testData/codeInsight/completion/normal/FieldType_after.java new file mode 100644 index 000000000000..071e1faf557b --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/FieldType_after.java @@ -0,0 +1,4 @@ +class A { + private long localizedStringManager; + +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/FinalBeforeMethodCall.java b/java/java-tests/testData/codeInsight/completion/normal/FinalBeforeMethodCall.java new file mode 100644 index 000000000000..c28c3b2dc1d6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/FinalBeforeMethodCall.java @@ -0,0 +1,5 @@ +class A { + A() { + finthis.toString(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferDeclared.java b/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferDeclared.java index e846cff17463..d2e0abca1ea5 100644 --- a/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferDeclared.java +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferDeclared.java @@ -2,6 +2,7 @@ public class Aaaaaaa { private final String aaa; Aaaaaaa(String aabbb) { + aaa = ""; aaa = true ? null : aa } diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferDeclaredOfExpectedType.java b/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferDeclaredOfExpectedType.java index 5d79d9702a89..4acc0b1cc375 100644 --- a/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferDeclaredOfExpectedType.java +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferDeclaredOfExpectedType.java @@ -2,6 +2,7 @@ public class Aaaaaaa { private final String aaa; Aaaaaaa(Object aabbb) { + aaa = ""; aaa = true ? null : aa } diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/PreferSameNamedMethods.java b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferSameNamedMethods.java new file mode 100644 index 000000000000..03d1003a0b7f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferSameNamedMethods.java @@ -0,0 +1,15 @@ +class Goo { + int boo() {} + int doo() {} + int foo() {} +} + +class Foooo { + Goo g; + + int foo() { + return g. + } + +} + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing-out.java b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing-out.java new file mode 100644 index 000000000000..bbf0f76d3cf6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing-out.java @@ -0,0 +1,8 @@ +class A { + public abstract void zoo(int y); + + { + Object x; + zoo((Integer) x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing.java b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing.java new file mode 100644 index 000000000000..661b6ea0de2d --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing.java @@ -0,0 +1,8 @@ +class A { + public abstract void zoo(int y); + + { + Object x; + zoo((x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing2-out.java b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing2-out.java new file mode 100644 index 000000000000..bbf0f76d3cf6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing2-out.java @@ -0,0 +1,8 @@ +class A { + public abstract void zoo(int y); + + { + Object x; + zoo((Integer) x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing2.java b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing2.java new file mode 100644 index 000000000000..fede6af603c5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing2.java @@ -0,0 +1,8 @@ +class A { + public abstract void zoo(int y); + + { + Object x; + zoo(() x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing3-out.java b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing3-out.java new file mode 100644 index 000000000000..bbf0f76d3cf6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing3-out.java @@ -0,0 +1,8 @@ +class A { + public abstract void zoo(int y); + + { + Object x; + zoo((Integer) x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing3.java b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing3.java new file mode 100644 index 000000000000..4df5d6ae846f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/CastAutoboxing3.java @@ -0,0 +1,8 @@ +class A { + public abstract void zoo(int y); + + { + Object x; + zoo((a) x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/CastWildcards-out.java b/java/java-tests/testData/codeInsight/completion/smartType/CastWildcards-out.java new file mode 100644 index 000000000000..307a275283ee --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/CastWildcards-out.java @@ -0,0 +1,6 @@ +abstract class A { + void foo(T x){} + void bar(A a, Object b){ + a.foo((Throwable) b); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/CastWildcards.java b/java/java-tests/testData/codeInsight/completion/smartType/CastWildcards.java new file mode 100644 index 000000000000..0570efc3184c --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/CastWildcards.java @@ -0,0 +1,6 @@ +abstract class A { + void foo(T x){} + void bar(A a, Object b){ + a.foo(() b); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsed-out.java b/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsed-out.java new file mode 100644 index 000000000000..f9430cdb29a0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsed-out.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2011 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. + */ +class MyClass { + public void foo() { + MyDD d = new MyDD() + } +} + +class MyDD { + MyDD(T t){} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsed.java b/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsed.java new file mode 100644 index 000000000000..69a12ec44ec7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsed.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2011 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. + */ +class MyClass { + public void foo() { + MyDD d = new MyD + } +} + +class MyDD { + MyDD(T t){} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetAbove-out.java b/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetAbove-out.java new file mode 100644 index 000000000000..cc99ed5c463a --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetAbove-out.java @@ -0,0 +1,9 @@ +class A { + int doo; + int aaa; + A(int b) { + doo = b; + aaa = doo; + } +} + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetAbove.java b/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetAbove.java new file mode 100644 index 000000000000..bad8dd3a2920 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetAbove.java @@ -0,0 +1,9 @@ +class A { + int doo; + int aaa; + A(int b) { + doo = b; + aaa = d + } +} + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetInAnotherConstructor-out.java b/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetInAnotherConstructor-out.java new file mode 100644 index 000000000000..f78838d00bf1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetInAnotherConstructor-out.java @@ -0,0 +1,13 @@ +class A { + int doo; + int aaa; + A(int b) { + doo = b; + } + + A(int aac, int aad) { + this(aac); + aaa = doo; + } +} + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetInAnotherConstructor.java b/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetInAnotherConstructor.java new file mode 100644 index 000000000000..51b47e14411a --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/FieldsSetInAnotherConstructor.java @@ -0,0 +1,13 @@ +class A { + int doo; + int aaa; + A(int b) { + doo = b; + } + + A(int aac, int aad) { + this(aac); + aaa = d + } +} + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoCommaBeforeVarargs-out.java b/java/java-tests/testData/codeInsight/completion/smartType/NoCommaBeforeVarargs-out.java new file mode 100644 index 000000000000..3d0404d5ba78 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoCommaBeforeVarargs-out.java @@ -0,0 +1,8 @@ +class Foooo { + int bar(int a, Object... varargs) {} + + int foo() { + bar(hashCode()); + } + +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoCommaBeforeVarargs.java b/java/java-tests/testData/codeInsight/completion/smartType/NoCommaBeforeVarargs.java new file mode 100644 index 000000000000..2d588132a9bf --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoCommaBeforeVarargs.java @@ -0,0 +1,8 @@ +class Foooo { + int bar(int a, Object... varargs) {} + + int foo() { + bar(ha); + } + +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoFieldsInSuperConstructorCall-out.java b/java/java-tests/testData/codeInsight/completion/smartType/NoFieldsInSuperConstructorCall-out.java new file mode 100644 index 000000000000..dd4e04b8048a --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoFieldsInSuperConstructorCall-out.java @@ -0,0 +1,11 @@ +class A { + A(int a) {} +} + +class B extends A { + int aaa; + + B(int aab) { + super(aab); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoFieldsInSuperConstructorCall.java b/java/java-tests/testData/codeInsight/completion/smartType/NoFieldsInSuperConstructorCall.java new file mode 100644 index 000000000000..654cfc42cf98 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoFieldsInSuperConstructorCall.java @@ -0,0 +1,11 @@ +class A { + A(int a) {} +} + +class B extends A { + int aaa; + + B(int aab) { + super(a); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoSecondMethodTypeArguments-out.java b/java/java-tests/testData/codeInsight/completion/smartType/NoSecondMethodTypeArguments-out.java new file mode 100644 index 000000000000..ffd936e30b6f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoSecondMethodTypeArguments-out.java @@ -0,0 +1,9 @@ +import java.util.Collections; +import java.util.List; + +class A { + void foo(List x){} + { + foo(Collections.emptyList()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoSecondMethodTypeArguments.java b/java/java-tests/testData/codeInsight/completion/smartType/NoSecondMethodTypeArguments.java new file mode 100644 index 000000000000..d81ea0d791b3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoSecondMethodTypeArguments.java @@ -0,0 +1,9 @@ +import java.util.Collections; +import java.util.List; + +class A { + void foo(List x){} + { + foo(Collections.emptyList()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoUninitializedFieldsInConstructor-out.java b/java/java-tests/testData/codeInsight/completion/smartType/NoUninitializedFieldsInConstructor-out.java new file mode 100644 index 000000000000..e49b17247f65 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoUninitializedFieldsInConstructor-out.java @@ -0,0 +1,8 @@ +class A { + int aaa; + int aab; + A(int aac) { + aaa = aac; + } +} + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoUninitializedFieldsInConstructor.java b/java/java-tests/testData/codeInsight/completion/smartType/NoUninitializedFieldsInConstructor.java new file mode 100644 index 000000000000..4d45189923f9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoUninitializedFieldsInConstructor.java @@ -0,0 +1,8 @@ +class A { + int aaa; + int aab; + A(int aac) { + aaa = a + } +} + diff --git a/java/java-tests/testData/codeInsight/completion/smartType/ThisFieldAssignedToItself.java b/java/java-tests/testData/codeInsight/completion/smartType/ThisFieldAssignedToItself.java new file mode 100644 index 000000000000..93b10fb8f3f8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/ThisFieldAssignedToItself.java @@ -0,0 +1,8 @@ +class A { + Object field; + + A() { + field = 2; + this.field = fi + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/second/NonInitializedField-out.java b/java/java-tests/testData/codeInsight/completion/smartType/second/NonInitializedField-out.java new file mode 100644 index 000000000000..b74ac99da84f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/second/NonInitializedField-out.java @@ -0,0 +1,7 @@ +class Foo { + int aaa; + int bbb; + Foo() { + aaa = bbb; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/second/NonInitializedField.java b/java/java-tests/testData/codeInsight/completion/smartType/second/NonInitializedField.java new file mode 100644 index 000000000000..e8eee5d953f6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/second/NonInitializedField.java @@ -0,0 +1,7 @@ +class Foo { + int aaa; + int bbb; + Foo() { + aaa = b + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferSameNamedMethods.java b/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferSameNamedMethods.java new file mode 100644 index 000000000000..fff5241c35a8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferSameNamedMethods.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2011 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. + */ +class Goo { + int boo() {} + int doo() {} + int foo() {} +} + +class Foooo { + Goo g; + + int foo() { + return g. + } + +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java index a3c496807427..1258a5350bf8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java @@ -35,11 +35,41 @@ class P { class Test1 { void bar() { - foo(new FF<>()); + foo(new FF<>()); } void foo(F> p) {} } class FF extends F{} -class F {} \ No newline at end of file +class F {} + +class MyTest { + static class Foo { + Foo(X x) {} + } + + static interface Base {} + static class A extends Exception implements Base {} + static class B extends Exception implements Base {} + + void m() throws B { + try { + if (true) { + throw new A(); + } + else { + throw new B(); + } + } catch (A ex) { + Foo> foo1 = new Foo<>(ex); // ok + Foo> foo2 = new Foo<>(ex); // should be error + } + } +} + +class NonParameterized { + void foo() { + new NonParameterized<>(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg1.java index ddf456df1746..220e99fd850a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg1.java @@ -8,29 +8,29 @@ class Neg01 { void test() { Neg01<String> n1 = new Neg01<>("" ); //new Foo created - Neg01<? extends String> n2 = new Neg01<>(""); //new Foo created - Neg01 n3 = new Neg01<>(""); //new Foo created + Neg01<? extends String> n2 = new Neg01<>(""); //new Foo created + Neg01 n3 = new Neg01<>(""); //new Foo created Neg01<? super String> n4 = new Neg01<>(""); //new Foo created Neg01<String> n5 = new Neg01<>("") { }; //new Foo created - Neg01<? extends String> n6 = new Neg01<>("") { + Neg01<? extends String> n6 = new Neg01<>("") { }; //new Foo created - Neg01 n7 = new Neg01<>("") { + Neg01 n7 = new Neg01<>("") { }; //new Foo created Neg01<? super String> n8 = new Neg01<>("") { }; //new Foo created Neg01<String> n9 = new Neg01<>("", ""); //new Foo created - Neg01<? extends String> n10 = new Neg01<>("", ""); //new Foo created - Neg01 n11 = new Neg01<>("", ""); //new Foo created + Neg01<? extends String> n10 = new Neg01<>("", ""); //new Foo created + Neg01 n11 = new Neg01<>("", ""); //new Foo created Foo n12 = new Neg01<>("", ""); //new Foo created Neg01<String> n13 = new Neg01<>("", "") { }; //new Foo created - Neg01<? extends String> n14 = new Neg01<>("", "") { + Neg01<? extends String> n14 = new Neg01<>("", "") { }; //new Foo created - Neg01 n15 = new Neg01<>("", "") { + Neg01 n15 = new Neg01<>("", "") { }; //new Foo created Neg01<? super String> n16 = new Neg01<>("", "") { }; //new Foo created diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg10.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg10.java new file mode 100644 index 000000000000..e5efd0968f05 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg10.java @@ -0,0 +1,7 @@ +class Neg10 { + static class Foo { + Foo(X x) {} + } + + Foo fw = new Foo<>(1); +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg11.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg11.java new file mode 100644 index 000000000000..3e32e1a49071 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg11.java @@ -0,0 +1,8 @@ +class Neg11 { + + void test() { + class Foo { } + Foo f1 = new UndeclaredName<>(); //this is deliberate: aim is to test erroneous path + Foo f2 = new UndeclaredName<>() {}; //this is deliberate: aim is to test erroneous path + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg2.java index 635dc5bd9798..9a218866a1ce 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg2.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg2.java @@ -10,29 +10,29 @@ class Neg02 { void testSimple() { Foo<String> f1 = new Foo<>(""); //new Foo created - Foo<? extends String> f2 = new Foo<>(""); //new Foo created - Foo f3 = new Foo<>(""); //new Foo created + Foo<? extends String> f2 = new Foo<>(""); //new Foo created + Foo f3 = new Foo<>(""); //new Foo created Foo<? super String> f4 = new Foo<>(""); //new Foo created Foo<String> f5 = new Foo<>("") { }; //new Foo created - Foo<? extends String> f6 = new Foo<>("") { + Foo<? extends String> f6 = new Foo<>("") { }; //new Foo created - Foo f7 = new Foo< >("") { + Foo f7 = new Foo< >("") { }; //new Foo created Foo<? super String> f8 = new Foo<>("") { }; //new Foo created Foo<String> f9 = new Foo<>("", ""); //new Foo created - Foo<? extends String> f10 = new Foo<>("", ""); //new Foo created - Foo f11 = new Foo< >("", ""); //new Foo created + Foo<? extends String> f10 = new Foo<>("", ""); //new Foo created + Foo f11 = new Foo< >("", ""); //new Foo created Foo<? super String> f12 = new Foo<>("", ""); //new Foo created Foo<String> f13 = new Foo<>("", "") { }; //new Foo created - Foo<? extends String> f14 = new Foo<>("", "") { + Foo<? extends String> f14 = new Foo<>("", "") { }; //new Foo created - Foo f15 = new Foo< >("", "") { + Foo f15 = new Foo< >("", "") { }; //new Foo created Foo<? super String> f16 = new Foo<>("", "") { }; //new Foo created @@ -40,29 +40,29 @@ class Neg02 { void testQualified() { Foo<String> f1 = new Neg02.Foo<>(""); //new Foo created - Foo<? extends String> f2 = new Neg02.Foo<>(""); //new Foo created - Foo f3 = new Neg02.Foo< >(""); //new Foo created + Foo<? extends String> f2 = new Neg02.Foo<>(""); //new Foo created + Foo f3 = new Neg02.Foo< >(""); //new Foo created Foo<? super String> f4 = new Neg02.Foo<>(""); //new Foo created Foo<String> f5 = new Neg02.Foo<>("") { }; //new Foo created - Foo<? extends String> f6 = new Neg02.Foo<>("") { + Foo<? extends String> f6 = new Neg02.Foo<>("") { }; //new Foo created - Foo f7 = new Neg02.Foo< >("") { + Foo f7 = new Neg02.Foo< >("") { }; //new Foo created Foo<? super String> f8 = new Neg02.Foo<>("") { }; //new Foo created Foo<String> f9 = new Neg02.Foo<>("", ""); //new Foo created - Foo<? extends String> f10 = new Neg02.Foo<>("", ""); //new Foo created - Foo f11 = new Neg02.Foo< >("", ""); //new Foo created + Foo<? extends String> f10 = new Neg02.Foo<>("", ""); //new Foo created + Foo f11 = new Neg02.Foo< >("", ""); //new Foo created Foo<? super String> f12 = new Neg02.Foo<>("", ""); //new Foo created Foo<String> f13 = new Neg02.Foo<>("", "") { }; //new Foo created - Foo<? extends String> f14 = new Neg02.Foo<>("", "") { + Foo<? extends String> f14 = new Neg02.Foo<>("", "") { }; //new Foo created - Foo f15 = new Neg02.Foo< >("", "") { + Foo f15 = new Neg02.Foo< >("", "") { }; //new Foo created Foo<? super String> f16 = new Neg02.Foo<>("", "") { }; //new Foo created diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg3.java index 8d770ab57870..6b2a82b9227d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg3.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg3.java @@ -7,67 +7,67 @@ class Neg03 { void testSimple() { Foo<String> f1 = new Foo<>(""); //new Foo created - Foo<? extends String> f2 = new Foo<>(""); //new Foo created - Foo f3 = new Foo<>(""); //new Foo created + Foo<? extends String> f2 = new Foo<>(""); //new Foo created + Foo f3 = new Foo<>(""); //new Foo created Foo<? super String> f4 = new Foo<>(""); //new Foo created Foo<String> f5 = new Foo<>(""){}; //new Foo created - Foo<? extends String> f6 = new Foo<>(""){}; //new Foo created - Foo f7 = new Foo<>(""){}; //new Foo created + Foo<? extends String> f6 = new Foo<>(""){}; //new Foo created + Foo f7 = new Foo<>(""){}; //new Foo created Foo<? super String> f8 = new Foo<>(""){}; //new Foo created Foo<String> f9 = new Foo<>("", ""); //new Foo created - Foo<? extends String> f10 = new Foo<>("", ""); //new Foo created - Foo f11 = new Foo<>("", ""); //new Foo created + Foo<? extends String> f10 = new Foo<>("", ""); //new Foo created + Foo f11 = new Foo<>("", ""); //new Foo created Foo<? super String> f12 = new Foo<>("", ""); //new Foo created Foo<String> f13 = new Foo<>("", ""){}; //new Foo created - Foo<? extends String> f14 = new Foo<>("", ""){}; //new Foo created - Foo f15 = new Foo<>("", ""){}; //new Foo created + Foo<? extends String> f14 = new Foo<>("", ""){}; //new Foo created + Foo f15 = new Foo<>("", ""){}; //new Foo created Foo<? super String> f16 = new Foo<>("", ""){}; //new Foo created } void testQualified_1() { Foo<String> f1 = new Neg03.Foo<>(""); //new Foo created - Foo<? extends String> f2 = new Neg03.Foo<>(""); //new Foo created - Foo f3 = new Neg03.Foo<>(""); //new Foo created + Foo<? extends String> f2 = new Neg03.Foo<>(""); //new Foo created + Foo f3 = new Neg03.Foo<>(""); //new Foo created Foo<? super String> f4 = new Neg03.Foo<>(""); //new Foo created Foo<String> f5 = new Neg03.Foo<>(""){}; //new Foo created - Foo<? extends String> f6 = new Neg03.Foo<>(""){}; //new Foo created - Foo f7 = new Neg03.Foo<>(""){}; //new Foo created + Foo<? extends String> f6 = new Neg03.Foo<>(""){}; //new Foo created + Foo f7 = new Neg03.Foo<>(""){}; //new Foo created Foo<? super String> f8 = new Neg03.Foo<>(""){}; //new Foo created Foo<String> f9 = new Neg03.Foo<>("", ""); //new Foo created - Foo<? extends String> f10 = new Neg03.Foo<>("", ""); //new Foo created - Foo f11 = new Neg03.Foo<>("", ""); //new Foo created + Foo<? extends String> f10 = new Neg03.Foo<>("", ""); //new Foo created + Foo f11 = new Neg03.Foo<>("", ""); //new Foo created Foo<? super String> f12 = new Neg03.Foo<>("", ""); //new Foo created Foo<String> f13 = new Neg03.Foo<>("", ""){}; //new Foo created - Foo<? extends String> f14 = new Neg03.Foo<>("", ""){}; //new Foo created - Foo f15 = new Neg03.Foo<>("", ""){}; //new Foo created + Foo<? extends String> f14 = new Neg03.Foo<>("", ""){}; //new Foo created + Foo f15 = new Neg03.Foo<>("", ""){}; //new Foo created Foo<? super String> f16 = new Neg03.Foo<>("", ""){}; //new Foo created } void testQualified_2(Neg03 n) { Foo<String> f1 = n.new Foo<>(""); //new Foo created - Foo<? extends String> f2 = n.new Foo<>(""); //new Foo created - Foo f3 = n.new Foo<>(""); //new Foo created + Foo<? extends String> f2 = n.new Foo<>(""); //new Foo created + Foo f3 = n.new Foo<>(""); //new Foo created Foo<? super String> f4 = n.new Foo<>(""); //new Foo created Foo<String> f5 = n.new Foo<>(""){}; //new Foo created - Foo<? extends String> f6 = n.new Foo<>(""){}; //new Foo created - Foo f7 = n.new Foo<>(""){}; //new Foo created + Foo<? extends String> f6 = n.new Foo<>(""){}; //new Foo created + Foo f7 = n.new Foo<>(""){}; //new Foo created Foo<? super String> f8 = n.new Foo<>(""){}; //new Foo created Foo<String> f9 = n.new Foo<>("", ""); //new Foo created - Foo<? extends String> f10 = n.new Foo<>("", ""); //new Foo created - Foo f11 = n.new Foo<>("", ""); //new Foo created + Foo<? extends String> f10 = n.new Foo<>("", ""); //new Foo created + Foo f11 = n.new Foo<>("", ""); //new Foo created Foo<? super String> f12 = n.new Foo<>("", ""); //new Foo created Foo<String> f13 = n.new Foo<>("", ""){}; //new Foo created - Foo<? extends String> f14 = n.new Foo<>("", ""){}; //new Foo created - Foo f15 = n.new Foo<>("", ""){}; //new Foo created + Foo<? extends String> f14 = n.new Foo<>("", ""){}; //new Foo created + Foo f15 = n.new Foo<>("", ""){}; //new Foo created Foo<? super String> f16 = n.new Foo<>("", ""){}; //new Foo created } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg4.java index 30b124f56668..204dd9fcc155 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg4.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg4.java @@ -6,23 +6,23 @@ class Neg04 { Foo(V x, Z z) {} } Foo<String> n1 = new Foo<>(""); //new Foo created - Foo<? extends String> n2 = new Foo<>(""); //new Foo created - Foo n3 = new Foo<>(""); //new Foo created + Foo<? extends String> n2 = new Foo<>(""); //new Foo created + Foo n3 = new Foo<>(""); //new Foo created Foo<? super String> n4 = new Foo<>(""); //new Foo created Foo<String> n5 = new Foo<>(""){}; //new Foo created - Foo<? extends String> n6 = new Foo<>(""){}; //new Foo created - Foo n7 = new Foo<>(""){}; //new Foo created + Foo<? extends String> n6 = new Foo<>(""){}; //new Foo created + Foo n7 = new Foo<>(""){}; //new Foo created Foo<? super String> n8 = new Foo<>(""){}; //new Foo created Foo<String> n9 = new Foo<>("", ""); //new Foo created - Foo<? extends String> n10 = new Foo<>("", ""); //new Foo created - Foo n11 = new Foo<>("", ""); //new Foo created + Foo<? extends String> n10 = new Foo<>("", ""); //new Foo created + Foo n11 = new Foo<>("", ""); //new Foo created Foo<? super String> n12 = new Foo<>("", ""); //new Foo created Foo<String> n13 = new Foo<>("", ""){}; //new Foo created - Foo<? extends String> n14 = new Foo<>("", ""){}; //new Foo created - Foo n15 = new Foo<>("", ""){}; //new Foo created + Foo<? extends String> n14 = new Foo<>("", ""){}; //new Foo created + Foo n15 = new Foo<>("", ""){}; //new Foo created Foo<? super String> n16 = new Foo<>("", ""){}; //new Foo created } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg6.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg6.java new file mode 100644 index 000000000000..585761fb8216 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg6.java @@ -0,0 +1,11 @@ +class Neg06 { + interface ISuperFoo {} + interface IFoo extends ISuperFoo {} + + static class CSuperFoo {} + static class CFoo extends CSuperFoo {} + + ISuperFoo isf = new IFoo<>() {}; + CSuperFoo csf1 = new CFoo<>(); + CSuperFoo csf2 = new CFoo<>() {}; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg7.java new file mode 100644 index 000000000000..5bdbff54f378 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg7.java @@ -0,0 +1,9 @@ +class Neg07 { + static class SuperFoo {} + static class Foo extends SuperFoo { + Foo(X x) {} + } + + SuperFoo sf1 = new Foo<>(""); + SuperFoo sf2 = new Foo<>("") {}; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg8.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg8.java new file mode 100644 index 000000000000..060efa6ebe7b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg8.java @@ -0,0 +1,20 @@ +class Neg08 { + static class Foo { + Foo(X x) { } + } + + static class DoubleFoo { + DoubleFoo(X x,Y y) { } + } + + static class TripleFoo { + TripleFoo(X x,Y y,Z z) { } + } + + Foo fi = new Foo<>(1); + Foo fw = new Foo<>(fi); + Foo fd = new Foo<>(3.0); + DoubleFoo dw = new DoubleFoo<>(fi,fd); + Foo fs = new Foo<>("one"); + TripleFoo tw = new TripleFoo<>(fi,fd,fs); +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg9.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg9.java new file mode 100644 index 000000000000..5bca169e0f2d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondNeg9.java @@ -0,0 +1,12 @@ +class Neg09 { + static class Foo> {} + static class DoubleFoo, + Y extends Number & Comparable> {} + static class TripleFoo, + Y extends Number & Comparable, + Z> {} + + Foo fw = new Foo<>(); + DoubleFoo dw = new DoubleFoo<>(); + TripleFoo tw = new TripleFoo<>(); +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondPos5.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondPos5.java new file mode 100644 index 000000000000..1f60451ae16d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondPos5.java @@ -0,0 +1,12 @@ +public class Pos05 { + + static class Foo { + Foo(X x) {} + } + + void m(Foo fi) {} + + void test() { + m(new Foo<>(1)); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResources.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResources.java index 750e9bc5cb0e..fa8f950ef4b1 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResources.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResources.java @@ -1,31 +1,69 @@ -import java.io.*; -import java.lang.Exception; - class C { - void m0() throws Exception { - try (FileReader reader = new FileReader(new File("input.txt"))) { - reader.read(); - } catch (Exception e) { - reader = null; - } - reader = null; + static class E extends Exception { } + static class E1 extends E { } + static class E2 extends E { } + static class E3 extends E { } + + static class MyResource implements AutoCloseable { + public MyResource() throws E1 { } + public void doSomething() throws E2 { } + @Override public void close() throws E3 { } } void m1() { - try (final FileReader reader = new FileReader(new File("input.txt"))) { - reader.read(); - } - catch (IOException ignore) { } + try (MyResource r = new MyResource()) { r.doSomething(); } + catch (E1 | E2 | E3 ignore) { } - try (final FileReader reader = new FileReader(new File("input.txt"))) { - System.out.println("Try."); - } - catch (IOException ignore) { } + try (new MyResource()) { } + catch (E1 | E3 ignore) { } + + MyResource r; + + try (r = new MyResource()) { } + catch (E1 e) { } + + try (r = new MyResource()) { } + catch (E3 e) { } + + try (r = new MyResource()) { } } - /*void m2() throws IOException { - try (final FileReader reader = new FileReader(new File("input.txt"))) { - reader.read(); + void m2() throws Exception { + try (Object r = new MyResource()) { } + + try ("resource") { } + } + + void m3(int p) throws Exception { + try (MyResource r = new MyResource()) { + r.doSomething(); + r = null; + int r = 0; } - }*/ + catch (E e) { + r = null; + } + finally { + r = null; + } + r = null; + + try (MyResource r = new MyResource(); MyResource r = new MyResource()) { } + + try (MyResource r1 = new MyResource(); MyResource r2 = r1) { } + + /* todo: try (MyResource r1 = < error descr="Cannot resolve symbol 'r'">r2; MyResource r2 = r1) { }*/ + + MyResource r = null; + try (MyResource r = new MyResource()) { } + try (r = new MyResource()) { } + + try (MyResource p = new MyResource()) { } + new Runnable() { + public void run() { + try (MyResource p = new MyResource()) { } + catch (E e) { } + } + }.run(); + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java new file mode 100644 index 000000000000..68b4fb4b4925 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java @@ -0,0 +1,41 @@ +import java.lang.Exception; + +class C { + static class MyResource implements AutoCloseable { + @Override public void close() { } + } + + void m1() throws Exception { + MyResource r1; + try (r1 = new MyResource()) { + System.out.println(r1); + } + + try (MyResource r2 = new MyResource()) { + System.out.println(r2); + } + + MyResource r3 = new MyResource(); + try (MyResource r = r3) { + System.out.println(r); + } + } + + void m2() throws Exception { + MyResource r1 = null; + try (r1 = new MyResource()) { + System.out.println(r1); + } + + MyResource r2 = null; + System.out.println(r2); + try (r2 = new MyResource()) { } + + try (MyResource r3 = new MyResource()) { } + + MyResource r4; + try (MyResource r = r4) { + System.out.println(r); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after2.java deleted file mode 100644 index 0a5023e89f44..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after2.java +++ /dev/null @@ -1,7 +0,0 @@ -// "Replace with <>" "true" -public class Test { - F> f = new FF<>(); -} - -class FF extends F{} -class F {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after3.java deleted file mode 100644 index 2e9b69d52d2e..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after3.java +++ /dev/null @@ -1,11 +0,0 @@ -// "Replace with <>" "true" -public class Test { - void bar() { - foo(new FF<>()); - } - - void foo(F> p) {} -} - -class FF extends F{} -class F {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after5.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after5.java new file mode 100644 index 000000000000..dcc744c23ae5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after5.java @@ -0,0 +1,16 @@ +// "Replace with <>" "true" +class Test { + + void test() { + class Foo { + Foo() {} + Foo(X x) {} + } + Foo f1 = new Foo(1); + Foo f2 = new Foo<>(); + Foo f3 = new Foo(); + Foo f4 = new Foo(1) {}; + Foo f5 = new Foo() {}; + Foo f6 = new Foo() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after6.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after6.java new file mode 100644 index 000000000000..3f9bf24dbb06 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after6.java @@ -0,0 +1,16 @@ +// "Replace with <>" "true" +class Test { + + void test() { + class Foo { + Foo() {} + Foo(X x) {} + } + Foo f1 = new Foo(1); + Foo f2 = new Foo(); + Foo f3 = new Foo<>(); + Foo f4 = new Foo(1) {}; + Foo f5 = new Foo() {}; + Foo f6 = new Foo() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after8.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after8.java new file mode 100644 index 000000000000..06cc7b7973bb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after8.java @@ -0,0 +1,16 @@ +// "Replace with <>" "true" +class Test { + + void test() { + class Foo { + Foo() {} + Foo(X x) {} + } + Foo f1 = new Foo(1); + Foo f2 = new Foo(); + Foo f3 = new Foo(); + Foo f4 = new Foo(1) {}; + Foo f5 = new Foo<>() {}; + Foo f6 = new Foo() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after9.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after9.java new file mode 100644 index 000000000000..550518376f67 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/after9.java @@ -0,0 +1,16 @@ +// "Replace with <>" "true" +class Test { + + void test() { + class Foo { + Foo() {} + Foo(X x) {} + } + Foo f1 = new Foo(1); + Foo f2 = new Foo(); + Foo f3 = new Foo(); + Foo f4 = new Foo(1) {}; + Foo f5 = new Foo() {}; + Foo f6 = new Foo<>() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before2.java index 79e9cbcaad8e..eb4a2cf0e6e5 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before2.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before2.java @@ -1,4 +1,4 @@ -// "Replace with <>" "true" +// "Replace with <>" "false" public class Test { F> f = new FFing>(); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before3.java index d6d74cdc0908..8a08536a3ef5 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before3.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before3.java @@ -1,4 +1,4 @@ -// "Replace with <>" "true" +// "Replace with <>" "false" public class Test { void bar() { foo(new FFing>()); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before4.java new file mode 100644 index 000000000000..35cf27363787 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before4.java @@ -0,0 +1,16 @@ +// "Replace with <>" "false" +class Test { + + void test() { + class Foo { + Foo() {} + Foo(X x) {} + } + Foo f1 = new Foomber>(1); + Foo f2 = new Foo(); + Foo f3 = new Foo(); + Foo f4 = new Foo(1) {}; + Foo f5 = new Foo() {}; + Foo f6 = new Foo() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before5.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before5.java new file mode 100644 index 000000000000..6f8c5068e0e0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before5.java @@ -0,0 +1,16 @@ +// "Replace with <>" "true" +class Test { + + void test() { + class Foo { + Foo() {} + Foo(X x) {} + } + Foo f1 = new Foo(1); + Foo f2 = new Foober>(); + Foo f3 = new Foo(); + Foo f4 = new Foo(1) {}; + Foo f5 = new Foo() {}; + Foo f6 = new Foo() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before6.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before6.java new file mode 100644 index 000000000000..48666f4d3c4a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before6.java @@ -0,0 +1,16 @@ +// "Replace with <>" "true" +class Test { + + void test() { + class Foo { + Foo() {} + Foo(X x) {} + } + Foo f1 = new Foo(1); + Foo f2 = new Foo(); + Foo f3 = new Fooger>(); + Foo f4 = new Foo(1) {}; + Foo f5 = new Foo() {}; + Foo f6 = new Foo() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before7.java new file mode 100644 index 000000000000..1a0c0d45f200 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before7.java @@ -0,0 +1,16 @@ +// "Replace with <>" "false" +class Test { + + void test() { + class Foo { + Foo() {} + Foo(X x) {} + } + Foo f1 = new Foo(1); + Foo f2 = new Foo(); + Foo f3 = new Foo(); + Foo f4 = new Foomber>(1) {}; + Foo f5 = new Foo() {}; + Foo f6 = new Foo() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before8.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before8.java new file mode 100644 index 000000000000..0ce27b5983a4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before8.java @@ -0,0 +1,16 @@ +// "Replace with <>" "true" +class Test { + + void test() { + class Foo { + Foo() {} + Foo(X x) {} + } + Foo f1 = new Foo(1); + Foo f2 = new Foo(); + Foo f3 = new Foo(); + Foo f4 = new Foo(1) {}; + Foo f5 = new Fooer>() {}; + Foo f6 = new Foo() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before9.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before9.java new file mode 100644 index 000000000000..cd3b71989f5c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond/before9.java @@ -0,0 +1,16 @@ +// "Replace with <>" "true" +class Test { + + void test() { + class Foo { + Foo() {} + Foo(X x) {} + } + Foo f1 = new Foo(1); + Foo f2 = new Foo(); + Foo f3 = new Foo(); + Foo f4 = new Foo(1) {}; + Foo f5 = new Foo() {}; + Foo f6 = new Footeger>() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/after7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/after7.java new file mode 100644 index 000000000000..5b655ed5ba30 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/after7.java @@ -0,0 +1,14 @@ +// "Reuse previous variable 'r' declaration" "true" +import java.io.*; + +class a { + static class MyResource implements AutoCloseable { + public void close() { } + } + + void m() { + MyResource r; + try (r = new MyResource()) { + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/before7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/before7.java new file mode 100644 index 000000000000..dab83655490c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/before7.java @@ -0,0 +1,14 @@ +// "Reuse previous variable 'r' declaration" "true" +import java.io.*; + +class a { + static class MyResource implements AutoCloseable { + public void close() { } + } + + void m() { + MyResource r; + try (MyResource r = new MyResource()) { + } + } +} diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete10.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete10.txt index c9b9aaf68b6e..2e113f719226 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete10.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete10.txt @@ -1,7 +1,7 @@ PsiJavaFile:TryIncomplete10.java PsiTryStatement PsiKeyword:try('try') - PsiParameterList:( + PsiResourceList:( PsiJavaToken:LPARENTH('(') PsiErrorElement:')' expected diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete11.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete11.txt index 05e296fcc190..11b2811b4174 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete11.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete11.txt @@ -1,7 +1,7 @@ PsiJavaFile:TryIncomplete11.java PsiTryStatement PsiKeyword:try('try') - PsiParameterList:() + PsiResourceList:() PsiJavaToken:LPARENTH('(') PsiErrorElement:Resource definition expected diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete12.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete12.txt index 829a9a293c17..78a125c530b4 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete12.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete12.txt @@ -1,7 +1,7 @@ PsiJavaFile:TryIncomplete12.java PsiTryStatement PsiKeyword:try('try') - PsiParameterList:(;) + PsiResourceList:(;) PsiJavaToken:LPARENTH('(') PsiErrorElement:Resource definition expected diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete13.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete13.txt index 5883e80baf09..598f1ac3e5c0 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete13.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete13.txt @@ -1,18 +1,14 @@ PsiJavaFile:TryIncomplete13.java PsiTryStatement PsiKeyword:try('try') - PsiParameterList:(final ) + PsiResourceList:(final ) PsiJavaToken:LPARENTH('(') PsiModifierList:final PsiKeyword:final('final') - PsiErrorElement:Type expected + PsiErrorElement:Identifier or type expected PsiWhiteSpace(' ') - PsiTypeElement: - - PsiErrorElement:Identifier expected - PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') - PsiJavaToken:RBRACE('}') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete14.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete14.txt index 36386acc63b2..88a8aca925b2 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete14.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete14.txt @@ -1,18 +1,11 @@ PsiJavaFile:TryIncomplete14.java PsiTryStatement PsiKeyword:try('try') - PsiParameterList:(R) + PsiResourceList:(int) PsiJavaToken:LPARENTH('(') - PsiModifierList: - - PsiTypeElement:R - PsiJavaCodeReferenceElement:R - PsiIdentifier:R('R') - PsiReferenceParameterList - - PsiErrorElement:Identifier expected - + PsiErrorElement:Resource definition expected + PsiKeyword:int('int') PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') - PsiJavaToken:RBRACE('}') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete15.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete15.txt index f38fe8b04bc7..5748458436f0 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete15.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete15.txt @@ -1,20 +1,21 @@ PsiJavaFile:TryIncomplete15.java PsiTryStatement PsiKeyword:try('try') - PsiParameterList:(R r) + PsiResourceList:(R r) PsiJavaToken:LPARENTH('(') - PsiParameter:r - PsiModifierList: - - PsiTypeElement:R - PsiJavaCodeReferenceElement:R - PsiIdentifier:R('R') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r('r') - PsiErrorElement:'=' expected - + PsiResource:r + PsiLocalVariable:r + PsiModifierList: + + PsiTypeElement:R + PsiJavaCodeReferenceElement:R + PsiIdentifier:R('R') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiErrorElement:'=' expected + PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete16.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete16.txt index d18696953396..e04ca47331f8 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete16.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete16.txt @@ -1,22 +1,23 @@ PsiJavaFile:TryIncomplete16.java PsiTryStatement PsiKeyword:try('try') - PsiParameterList:(R r =) + PsiResourceList:(R r =) PsiJavaToken:LPARENTH('(') - PsiParameter:r - PsiModifierList: - - PsiTypeElement:R - PsiJavaCodeReferenceElement:R - PsiIdentifier:R('R') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r('r') - PsiWhiteSpace(' ') - PsiJavaToken:EQ('=') - PsiErrorElement:Expression expected - + PsiResource:r + PsiLocalVariable:r + PsiModifierList: + + PsiTypeElement:R + PsiJavaCodeReferenceElement:R + PsiIdentifier:R('R') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiErrorElement:Expression expected + PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete17.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete17.txt index 4f8626c450a0..e4f111fb50c8 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete17.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete17.txt @@ -1,23 +1,24 @@ PsiJavaFile:TryIncomplete17.java PsiTryStatement PsiKeyword:try('try') - PsiParameterList:(R r = 0;) + PsiResourceList:(R r = 0;) PsiJavaToken:LPARENTH('(') - PsiParameter:r - PsiModifierList: - - PsiTypeElement:R - PsiJavaCodeReferenceElement:R - PsiIdentifier:R('R') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r('r') - PsiWhiteSpace(' ') - PsiJavaToken:EQ('=') - PsiWhiteSpace(' ') - PsiLiteralExpression:0 - PsiJavaToken:INTEGER_LITERAL('0') + PsiResource:r + PsiLocalVariable:r + PsiModifierList: + + PsiTypeElement:R + PsiJavaCodeReferenceElement:R + PsiIdentifier:R('R') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') PsiJavaToken:SEMICOLON(';') PsiErrorElement:Identifier or type expected diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryNormal4.txt b/java/java-tests/testData/psi/parser-partial/statements/TryNormal4.txt index 29b541335e1f..c3bec38b2bf4 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryNormal4.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryNormal4.txt @@ -1,23 +1,24 @@ PsiJavaFile:TryNormal4.java PsiTryStatement PsiKeyword:try('try') - PsiParameterList:(R r = 0) + PsiResourceList:(R r = 0) PsiJavaToken:LPARENTH('(') - PsiParameter:r - PsiModifierList: - - PsiTypeElement:R - PsiJavaCodeReferenceElement:R - PsiIdentifier:R('R') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r('r') - PsiWhiteSpace(' ') - PsiJavaToken:EQ('=') - PsiWhiteSpace(' ') - PsiLiteralExpression:0 - PsiJavaToken:INTEGER_LITERAL('0') + PsiResource:r + PsiLocalVariable:r + PsiModifierList: + + PsiTypeElement:R + PsiJavaCodeReferenceElement:R + PsiIdentifier:R('R') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryNormal5.txt b/java/java-tests/testData/psi/parser-partial/statements/TryNormal5.txt index 78c53a180d3c..b69bed12f700 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryNormal5.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryNormal5.txt @@ -1,40 +1,42 @@ PsiJavaFile:TryNormal5.java PsiTryStatement PsiKeyword:try('try') - PsiParameterList:(R1 r1 = 1; R2 r2 = 2) + PsiResourceList:(R1 r1 = 1; R2 r2 = 2) PsiJavaToken:LPARENTH('(') - PsiParameter:r1 - PsiModifierList: - - PsiTypeElement:R1 - PsiJavaCodeReferenceElement:R1 - PsiIdentifier:R1('R1') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r1('r1') - PsiWhiteSpace(' ') - PsiJavaToken:EQ('=') - PsiWhiteSpace(' ') - PsiLiteralExpression:1 - PsiJavaToken:INTEGER_LITERAL('1') + PsiResource:r1 + PsiLocalVariable:r1 + PsiModifierList: + + PsiTypeElement:R1 + PsiJavaCodeReferenceElement:R1 + PsiIdentifier:R1('R1') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r1('r1') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') PsiJavaToken:SEMICOLON(';') PsiWhiteSpace(' ') - PsiParameter:r2 - PsiModifierList: - - PsiTypeElement:R2 - PsiJavaCodeReferenceElement:R2 - PsiIdentifier:R2('R2') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r2('r2') - PsiWhiteSpace(' ') - PsiJavaToken:EQ('=') - PsiWhiteSpace(' ') - PsiLiteralExpression:2 - PsiJavaToken:INTEGER_LITERAL('2') + PsiResource:r2 + PsiLocalVariable:r2 + PsiModifierList: + + PsiTypeElement:R2 + PsiJavaCodeReferenceElement:R2 + PsiIdentifier:R2('R2') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r2('r2') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryNormal6.txt b/java/java-tests/testData/psi/parser-partial/statements/TryNormal6.txt new file mode 100644 index 000000000000..bf1b0ed88fd3 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/TryNormal6.txt @@ -0,0 +1,14 @@ +PsiJavaFile:TryNormal6.java + PsiTryStatement + PsiKeyword:try('try') + PsiResourceList:(r) + PsiJavaToken:LPARENTH('(') + PsiResource: + PsiReferenceExpression:r + PsiReferenceParameterList + + PsiIdentifier:r('r') + PsiJavaToken:RPARENTH(')') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryNormal7.txt b/java/java-tests/testData/psi/parser-partial/statements/TryNormal7.txt new file mode 100644 index 000000000000..1299595c7a9b --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/statements/TryNormal7.txt @@ -0,0 +1,19 @@ +PsiJavaFile:TryNormal7.java + PsiTryStatement + PsiKeyword:try('try') + PsiResourceList:(r; null) + PsiJavaToken:LPARENTH('(') + PsiResource: + PsiReferenceExpression:r + PsiReferenceParameterList + + PsiIdentifier:r('r') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiResource: + PsiLiteralExpression:null + PsiJavaToken:NULL_KEYWORD('null') + PsiJavaToken:RPARENTH(')') + PsiCodeBlock + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index 1439b3b55f83..64ed0eedb9e9 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -429,9 +429,9 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase { public void testVerticalArrows() { testArrows false, false, 0, -1 - testArrows false, true, -1, 1 - testArrows true, false, 0, -1 - testArrows true, true, -1, 1 + testArrows false, true, 0, -1 + testArrows true, false, 0, 1 + testArrows true, true, 0, 1 } public void testHideOnOnePrefixVariant() { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java index fd8258dc7b90..5885f56d7787 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java @@ -159,8 +159,17 @@ public class KeywordCompletionTest extends LightCompletionTestCase { public void testExtendsInCastTypeParameters() throws Throwable { doTest(); } public void testExtendsWithRightContextInClassTypeParameters() throws Throwable { doTest(); } - public void testExtraBracketAfterFinally() throws Throwable { doTest(); } - public void testExtraBracketAfterFinally1() throws Throwable { doTest(); } + public void testExtraBracketAfterFinally() throws Throwable { + configureByFile(BASE_PATH + "/" + getTestName(false) + ".java"); + selectItem(myItems[1]); + checkResultByFile(BASE_PATH + "/" + getTestName(false) + "-out.java"); + } + + public void testExtraBracketAfterFinally1() throws Throwable { + configureByFile(BASE_PATH + "/" + getTestName(false) + ".java"); + selectItem(myItems[1]); + checkResultByFile(BASE_PATH + "/" + getTestName(false) + "-out.java"); + } public void testTrueInVariableDeclaration() throws Throwable { doTest(); } public void testNullInIf() throws Throwable { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java index e3b88bd2b5e5..7da3343c047e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java @@ -201,4 +201,8 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase { assertFalse(getLookup().getItems().get(0).getObject() instanceof PsiClass); } + public void testPreferSameNamedMethods() { + checkPreferredItems(0, "foo", "boo", "doo", "hashCode"); + } + } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index b32981e99d55..968c25cad396 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -356,10 +356,12 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { checkResult() } + public void testFieldType() throws Throwable { doTest(); } + public void testPackageInAnnoParam() throws Throwable { doTest(); } - + public void testClassLiteralInAnnoParam() throws Throwable { doTest(); } @@ -369,6 +371,7 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { } public void testLocalClassName() throws Throwable { doTest(); } + public void testAssigningFieldForTheFirstTime() throws Throwable { doTest(); } public void testClassTypeParameters() throws Throwable { configure() @@ -390,6 +393,11 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { assertOrderedEquals myFixture.lookupElementStrings, 'Zoooz', 'Zooooo' } + public void testFinalBeforeMethodCall() throws Throwable { + configure() + assertStringItems 'final', 'finalize' + } + public void testMethodParenthesesSpaces() throws Throwable { final settings = CodeStyleSettingsManager.getSettings(getProject()) settings.SPACE_BEFORE_METHOD_CALL_PARENTHESES = true @@ -582,6 +590,9 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { checkResult() } + public void testFieldNegation() throws Throwable { doTest('!');} + public void testDefaultInSwitch() throws Throwable { doTest()} + public void testSuperInConstructor() throws Throwable { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java index 85c3caba21ec..3415ee36487e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java @@ -7,8 +7,6 @@ import com.intellij.codeInsight.lookup.LookupElementDecorator; import com.intellij.codeInsight.lookup.LookupItem; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.lookup.impl.LookupImpl; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; import com.intellij.testFramework.IdeaTestUtil; import org.jetbrains.annotations.NonNls; @@ -67,6 +65,7 @@ public class SecondSmartTypeCompletionTest extends LightCompletionTestCase { checkResultByFile(BASE_PATH + "/" + getTestName(false) + "-out.java"); } + public void testNonInitializedField() throws Throwable { doTest(); } public void testIgnoreToString() throws Throwable { doTest(); } public void testDontIgnoreToStringInsideIt() throws Throwable { doTest(); } public void testDontIgnoreToStringInStringBuilders() throws Throwable { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType17CompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType17CompletionTest.java index bd05bbca53c3..7ee850dac128 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType17CompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType17CompletionTest.java @@ -49,6 +49,10 @@ public class SmartType17CompletionTest extends LightFixtureCompletionTestCase { doTest(); } + public void testDiamondNotCollapsed() throws Exception { + doTest(); + } + private void doTest() throws Exception { configureByFile("/" + getTestName(false) + ".java"); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.java index 319811803680..963a4bebb9b2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.java @@ -235,6 +235,10 @@ public class SmartTypeCompletionOrderingTest extends CompletionSortingTestCase { assertPreferredItems(0, "myFoo", "myBar"); } + public void testPreferSameNamedMethods() { + checkPreferredItems(0, "foo", "boo", "doo", "hashCode"); + } + @Override protected String getBasePath() { return JavaTestUtil.getRelativeJavaTestDataPath() + BASE_PATH; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index 61086af10243..bfa4827e4743 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -431,6 +431,18 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { public void testPrivateOverloads() throws Throwable { doTest(); } + public void testCastAutoboxing() throws Throwable { doActionItemTest(); } + public void testCastAutoboxing2() throws Throwable { doActionItemTest(); } + public void testCastAutoboxing3() throws Throwable { doActionItemTest(); } + public void testCastWildcards() throws Throwable { doTest(); } + + public void testNoSecondMethodTypeArguments() throws Throwable { doTest(Lookup.REPLACE_SELECT_CHAR); } + + public void testNoFieldsInSuperConstructorCall() throws Throwable { doTest(); } + public void testNoUninitializedFieldsInConstructor() throws Throwable { doTest(); } + public void testFieldsSetInAnotherConstructor() throws Throwable { doTest(); } + public void testFieldsSetAbove() throws Throwable { doTest(); } + public void testHonorSelection() throws Throwable { configureByTestName(); select(); @@ -875,6 +887,8 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { doTest(); } + public void testNoCommaBeforeVarargs() throws Throwable { doTest(); } + public void testEnumField() throws Throwable { doItemTest(); } @@ -947,6 +961,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { public void testWildcardedInstanceof3() throws Throwable { doTest(); } public void testCheckStaticImportsType() throws Throwable { doAntiTest(); } + public void testThisFieldAssignedToItself() throws Throwable { doAntiTest(); } public void testTypeVariableInstanceOf() throws Throwable { configureByTestName(); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingJdk7Test.java new file mode 100644 index 000000000000..3a2c666d74b2 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingJdk7Test.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon; + +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.defUse.DefUseInspection; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.pom.java.LanguageLevel; +import org.jetbrains.annotations.NonNls; + +/** + * This class intended for "heavily-loaded" tests only, e.g. those need to setup separate project directory structure to run + * For "lightweight" tests use LightAdvHighlightingTest + */ +public class AdvHighlightingJdk7Test extends DaemonAnalyzerTestCase { + @NonNls private static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/advHighlighting"; + + @Override + protected Sdk getTestProjectJdk() { + LanguageLevelProjectExtension.getInstance(myProject).setLanguageLevel(LanguageLevel.JDK_1_7); + return JavaSdkImpl.getMockJdk17("java 1.7"); + } + + @Override + protected LocalInspectionTool[] configureLocalInspectionTools() { + return new LocalInspectionTool[]{new DefUseInspection()}; + } + + public void testStaticImportConflict() throws Exception { + doTest(BASE_PATH + "/staticImportConflict/Usage.java", BASE_PATH + "/staticImportConflict", false, false); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java index e55f40743792..6b2196793939 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java @@ -42,6 +42,12 @@ import java.util.Collection; public class AdvHighlightingTest extends DaemonAnalyzerTestCase { @NonNls private static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/advHighlighting"; + @Override + protected Sdk getTestProjectJdk() { + LanguageLevelProjectExtension.getInstance(myProject).setLanguageLevel(LanguageLevel.JDK_1_4); + return JavaSdkImpl.getMockJdk14(); + } + public void testPackageLocals() throws Exception { doTest(BASE_PATH+"/packageLocals/x/sub/UsingMain.java", BASE_PATH+"/packageLocals", false, false); } public void testPackageLocalClassInTheMiddle() throws Exception { doTest(BASE_PATH+"/packageLocals/x/A.java", BASE_PATH+"/packageLocals", false, false); } @@ -63,14 +69,6 @@ public class AdvHighlightingTest extends DaemonAnalyzerTestCase { public void testProtectedFieldAccessFromOtherPackage() throws Exception { doTest(BASE_PATH+"/protectedAccessFromOtherPackage/a/A.java", BASE_PATH+"/protectedAccessFromOtherPackage", false, false); } public void testPackageLocalClassInTheMiddle1() throws Exception { doTest(BASE_PATH+"/foreignPackageInBetween/a/A1.java", BASE_PATH+"/foreignPackageInBetween", false, false); } - @Override - protected Sdk getTestProjectJdk() { - @NonNls boolean is50 = "StaticImportConflict".equals(getTestName(false)); - LanguageLevelProjectExtension.getInstance(myProject).setLanguageLevel(is50 ? LanguageLevel.JDK_1_5 : LanguageLevel.JDK_1_4); - return is50 ? JavaSdkImpl.getMockJdk17("java 1.5") : JavaSdkImpl.getMockJdk14(); - } - - public void testStaticImportConflict() throws Exception { doTest(BASE_PATH+"/staticImportConflict/Usage.java", BASE_PATH+"/staticImportConflict", false, false); } public void testImportOnDemand() throws Exception { doTest(BASE_PATH+"/importOnDemand/y/Y.java", BASE_PATH+"/importOnDemand", false, false); } public void testImportOnDemandVsSingle() throws Exception { doTest(BASE_PATH+"/importOnDemandVsSingle/y/Y.java", BASE_PATH+"/importOnDemandVsSingle", false, false); } public void testImportSingleVsSamePackage() throws Exception { doTest(BASE_PATH+"/importSingleVsSamePackage/y/Y.java", BASE_PATH+"/importSingleVsSamePackage", false, false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index 6b64c70d82de..83a619d5559d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -4,6 +4,7 @@ import com.intellij.ExtensionPoints; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; +import com.intellij.codeInspection.defUse.DefUseInspection; import com.intellij.codeInspection.reference.EntryPoint; import com.intellij.codeInspection.reference.RefElement; import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection; @@ -31,7 +32,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { @Override protected LocalInspectionTool[] configureLocalInspectionTools() { - return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UncheckedWarningLocalInspection()}; + return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UncheckedWarningLocalInspection(), new DefUseInspection()}; } public void testDuplicateAnnotations() throws Exception { @@ -58,6 +59,10 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { doTest(false, false); } + public void testDiamondPos5() throws Exception { + doTest(false, false); + } + public void testDiamondNeg1() throws Exception { doTest(false, false); } @@ -78,6 +83,32 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { doTest(false, false); } + public void testDiamondNeg6() throws Exception { + doTest(false, false); + } + + public void testDiamondNeg7() throws Exception { + doTest(false, false); + } + + public void testDiamondNeg8() throws Exception { + doTest(false, false); + } + + public void testDiamondNeg9() throws Exception { + doTest(false, false); + } + + public void testDiamondNeg10() throws Exception { + doTest(false, false); + } + + public void testDiamondNeg11() throws Exception { + doTest(false, false); + } + + + public void testDiamondMisc() throws Exception { doTest(false, false); } @@ -162,6 +193,10 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { doTest(false, false); } + public void testTryWithResourcesWarn() throws Exception { + doTest(true, false); + } + public void testSafeVarargsApplicability() throws Exception { doTest(true, false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReuseVariableDeclarationtTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReuseVariableDeclarationTest.java similarity index 75% rename from java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReuseVariableDeclarationtTest.java rename to java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReuseVariableDeclarationTest.java index ccedcb111a4c..043e67830c72 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReuseVariableDeclarationtTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReuseVariableDeclarationTest.java @@ -1,9 +1,7 @@ - package com.intellij.codeInsight.daemon.quickFix; - -public class ReuseVariableDeclarationtTest extends LightQuickFixTestCase { +public class ReuseVariableDeclarationTest extends LightQuickFixTestCase { public void test() throws Exception { doAllTests(); } @@ -11,6 +9,4 @@ public class ReuseVariableDeclarationtTest extends LightQuickFixTestCase { protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration"; } - } - diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/StatementParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/StatementParserTest.java index 7cf68cf63d66..df12da3f6c62 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/StatementParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/StatementParserTest.java @@ -122,6 +122,8 @@ public class StatementParserTest extends JavaParsingTestCase { public void testTryNormal3() { doParserTestJDK7("try{}catch(A|B e){}"); } public void testTryNormal4() { doParserTestJDK7("try(R r = 0){}"); } public void testTryNormal5() { doParserTestJDK7("try(R1 r1 = 1; R2 r2 = 2){}"); } + public void testTryNormal6() { doParserTestJDK7("try(r){}"); } + public void testTryNormal7() { doParserTestJDK7("try(r; null){}"); } public void testTryIncomplete0() { doParserTest("try"); } public void testTryIncomplete1() { doParserTest("try{}"); } public void testTryIncomplete2() { doParserTest("try{}catch"); } @@ -136,7 +138,7 @@ public class StatementParserTest extends JavaParsingTestCase { public void testTryIncomplete11() { doParserTestJDK7("try(){}"); } public void testTryIncomplete12() { doParserTestJDK7("try(;){}"); } public void testTryIncomplete13() { doParserTestJDK7("try(final ){}"); } - public void testTryIncomplete14() { doParserTestJDK7("try(R){}"); } + public void testTryIncomplete14() { doParserTestJDK7("try(int){}"); } public void testTryIncomplete15() { doParserTestJDK7("try(R r){}"); } public void testTryIncomplete16() { doParserTestJDK7("try(R r =){}"); } public void testTryIncomplete17() { doParserTestJDK7("try(R r = 0;){}"); } diff --git a/java/java-tests/testSrc/com/intellij/openapi/vfs/LocalFileSystemTest.java b/java/java-tests/testSrc/com/intellij/openapi/vfs/LocalFileSystemTest.java index 820ddfd6d8d6..017070824b74 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/vfs/LocalFileSystemTest.java +++ b/java/java-tests/testSrc/com/intellij/openapi/vfs/LocalFileSystemTest.java @@ -1,14 +1,19 @@ package com.intellij.openapi.vfs; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.impl.win32.Win32LocalFileSystem; import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.testFramework.IdeaTestCase; import com.intellij.testFramework.IdeaTestUtil; +import org.jetbrains.annotations.NonNls; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; import java.util.Arrays; public class LocalFileSystemTest extends IdeaTestCase{ @@ -219,4 +224,20 @@ public class LocalFileSystemTest extends IdeaTestCase{ ); } + + public static void setContentOnDisk(File file, byte[] bom, String content, Charset charset) throws IOException { + FileOutputStream stream = new FileOutputStream(file); + stream.write(bom); + OutputStreamWriter writer = new OutputStreamWriter(stream, charset); + writer.write(content); + writer.close(); + } + + public static VirtualFile createTempFile(@NonNls String ext, byte[] bom, @NonNls String content, Charset charset) throws IOException { + File temp = FileUtil.createTempFile("copy", "." + ext); + setContentOnDisk(temp, bom, content, charset); + + myFilesToDelete.add(temp); + return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(temp); + } } diff --git a/java/java-tests/testSrc/com/intellij/projectView/StructureViewUpdatingTest.java b/java/java-tests/testSrc/com/intellij/projectView/StructureViewUpdatingTest.java index d7ee434b124c..81a61b14b0ad 100644 --- a/java/java-tests/testSrc/com/intellij/projectView/StructureViewUpdatingTest.java +++ b/java/java-tests/testSrc/com/intellij/projectView/StructureViewUpdatingTest.java @@ -34,11 +34,9 @@ package com.intellij.projectView; import com.intellij.JavaTestUtil; import com.intellij.ide.structureView.impl.java.InheritedMembersFilter; import com.intellij.ide.structureView.newStructureView.StructureViewComponent; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; -import com.intellij.testFramework.IdeaTestUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -48,6 +46,7 @@ import com.intellij.psi.JavaDirectoryService; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiField; +import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.TestSourceBasedTestCase; import com.intellij.util.IncorrectOperationException; @@ -69,55 +68,55 @@ public class StructureViewUpdatingTest extends TestSourceBasedTestCase { final StructureViewComponent structureViewComponent = (StructureViewComponent)fileEditor.getStructureViewBuilder().createStructureView(fileEditor, myProject); final Document document = PsiDocumentManager.getInstance(myProject).getDocument(psiClass.getContainingFile()); - IdeaTestUtil.assertTreeEqual(structureViewComponent.getTree(), - "-Class1.java\n" + - " -Class1\n" + - " getValue():int\n" + - " getClass():Class\n" + - " hashCode():int\n" + - " equals(Object):boolean\n" + - " clone():Object\n" + - " toString():String\n" + - " notify():void\n" + - " notifyAll():void\n" + - " wait(long):void\n" + - " wait(long, int):void\n" + - " wait():void\n" + - " finalize():void\n" + - " myField1:boolean\n" + - " myField2:boolean\n"); + PlatformTestUtil.assertTreeEqual(structureViewComponent.getTree(), + "-Class1.java\n" + + " -Class1\n" + + " getValue():int\n" + + " getClass():Class\n" + + " hashCode():int\n" + + " equals(Object):boolean\n" + + " clone():Object\n" + + " toString():String\n" + + " notify():void\n" + + " notifyAll():void\n" + + " wait(long):void\n" + + " wait(long, int):void\n" + + " wait():void\n" + + " finalize():void\n" + + " myField1:boolean\n" + + " myField2:boolean\n"); - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { + new WriteCommandAction.Simple(getProject()) { @Override - public void run() { - + protected void run() throws Throwable { final int offset = document.getLineStartOffset(5); document.insertString(offset, " boolean myNewField = false;\n"); } - }, null, null); + }.execute().throwException(); + PsiDocumentManager.getInstance(myProject).commitDocument(document); - IdeaTestUtil.waitForAlarm(600); + PlatformTestUtil.waitForAlarm(600); //TreeUtil.expand(structureViewComponent.getTree(), 3); - IdeaTestUtil.assertTreeEqual(structureViewComponent.getTree(), "-Class1.java\n" + - " -Class1\n" + " getValue():int\n" + - " getClass():Class\n" + - " hashCode():int\n" + - " equals(Object):boolean\n" + - " clone():Object\n" + - " toString():String\n" + - " notify():void\n" + - " notifyAll():void\n" + - " wait(long):void\n" + - " wait(long, int):void\n" + - " wait():void\n" + - " finalize():void\n" + - " myField1:boolean\n" + - " myField2:boolean\n" + - " myNewField:boolean = false\n"); + PlatformTestUtil.assertTreeEqual(structureViewComponent.getTree(), "-Class1.java\n" + + " -Class1\n" + " getValue():int\n" + + " getClass():Class\n" + + " hashCode():int\n" + + " equals(Object):boolean\n" + + " clone():Object\n" + + " toString():String\n" + + " notify():void\n" + + " notifyAll():void\n" + + " wait(long):void\n" + + " wait(long, int):void\n" + + " wait():void\n" + + " finalize():void\n" + + " myField1:boolean\n" + + " myField2:boolean\n" + + " myNewField:boolean = false\n"); Disposer.dispose(structureViewComponent); @@ -138,31 +137,31 @@ public class StructureViewUpdatingTest extends TestSourceBasedTestCase { try { structureViewComponent.setActionActive(InheritedMembersFilter.ID, true); - IdeaTestUtil.assertTreeEqual(structureViewComponent.getTree(), "-Class2.java\n" + - " -Class2\n" + - " +InnerClass1\n" + - " +InnerClass2\n" + - " getValue():int\n" + - " myField1:boolean\n" + - " myField2:boolean\n" + - " myField3:boolean\n" + - " myField4:boolean\n"); + PlatformTestUtil.assertTreeEqual(structureViewComponent.getTree(), "-Class2.java\n" + + " -Class2\n" + + " +InnerClass1\n" + + " +InnerClass2\n" + + " getValue():int\n" + + " myField1:boolean\n" + + " myField2:boolean\n" + + " myField3:boolean\n" + + " myField4:boolean\n"); final PsiField innerClassField = psiClass.getInnerClasses()[0].getFields()[0]; structureViewComponent.select(innerClassField, true); - IdeaTestUtil.assertTreeEqual(structureViewComponent.getTree(), "-Class2.java\n" + - " -Class2\n" + - " -InnerClass1\n" + - " +InnerClass12\n" + - " myInnerClassField:int\n" + - " +InnerClass2\n" + - " getValue():int\n" + - " myField1:boolean\n" + - " myField2:boolean\n" + - " myField3:boolean\n" + - " myField4:boolean\n"); + PlatformTestUtil.assertTreeEqual(structureViewComponent.getTree(), "-Class2.java\n" + + " -Class2\n" + + " -InnerClass1\n" + + " +InnerClass12\n" + + " myInnerClassField:int\n" + + " +InnerClass2\n" + + " getValue():int\n" + + " myField1:boolean\n" + + " myField2:boolean\n" + + " myField3:boolean\n" + + " myField4:boolean\n"); CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { @Override @@ -175,25 +174,25 @@ public class StructureViewUpdatingTest extends TestSourceBasedTestCase { innerClassField.delete(); } catch (IncorrectOperationException e) { - assertTrue(e.getLocalizedMessage(), false); + fail(e.getLocalizedMessage()); } } }); } }, null, null); - IdeaTestUtil.waitForAlarm(600); + PlatformTestUtil.waitForAlarm(600); - IdeaTestUtil.assertTreeEqual(structureViewComponent.getTree(), "-Class2.java\n" + - " -Class2\n" + - " -InnerClass1\n" + - " +InnerClass12\n" + - " +InnerClass2\n" + - " getValue():int\n" + - " myField1:boolean\n" + - " myField2:boolean\n" + - " myField3:boolean\n" + - " myField4:boolean\n"); + PlatformTestUtil.assertTreeEqual(structureViewComponent.getTree(), "-Class2.java\n" + + " -Class2\n" + + " -InnerClass1\n" + + " +InnerClass12\n" + + " +InnerClass2\n" + + " getValue():int\n" + + " myField1:boolean\n" + + " myField2:boolean\n" + + " myField3:boolean\n" + + " myField4:boolean\n"); } finally { @@ -213,26 +212,26 @@ public class StructureViewUpdatingTest extends TestSourceBasedTestCase { (StructureViewComponent)fileEditor.getStructureViewBuilder().createStructureView(fileEditor, myProject); final JTree tree = structureViewComponent.getTree(); - IdeaTestUtil.assertTreeEqual(tree, "-test.xml\n" + - " -test\n" + - " +level1\n" + - " +level1\n" + - " +level1\n" + - " +level1\n"); + PlatformTestUtil.assertTreeEqual(tree, "-test.xml\n" + + " -test\n" + + " +level1\n" + + " +level1\n" + + " +level1\n" + + " +level1\n"); tree.expandPath(tree.getPathForRow(3)); - IdeaTestUtil.waitForAlarm(600); + PlatformTestUtil.waitForAlarm(600); - IdeaTestUtil.assertTreeEqual(tree, - "-test.xml\n" + - " -test\n" + - " +level1\n" + - " -level1\n" + - " +level2\n" + - " +level1\n" + - " +level1\n"); + PlatformTestUtil.assertTreeEqual(tree, + "-test.xml\n" + + " -test\n" + + " +level1\n" + + " -level1\n" + + " +level2\n" + + " +level1\n" + + " +level1\n"); Disposer.dispose(structureViewComponent); } @@ -246,4 +245,9 @@ public class StructureViewUpdatingTest extends TestSourceBasedTestCase { protected String getTestDataPath() { return JavaTestUtil.getJavaTestDataPath(); } + + @Override + protected boolean isRunInWriteAction() { + return false; + } } diff --git a/java/java-tests/testSrc/com/intellij/psi/JavaStubBuilderTest.java b/java/java-tests/testSrc/com/intellij/psi/JavaStubBuilderTest.java index 79d1c17fcc8f..3c3b631c413c 100644 --- a/java/java-tests/testSrc/com/intellij/psi/JavaStubBuilderTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/JavaStubBuilderTest.java @@ -254,6 +254,7 @@ public class JavaStubBuilderTest extends LightIdeaTestCase { " void m() {\n" + " int local = 0;\n" + " for (int loop = 0; loop < 10; loop++) ;\n" + + " try (Resource r = new Resource()) { }\n" + " }\n" + "}", @@ -296,28 +297,6 @@ public class JavaStubBuilderTest extends LightIdeaTestCase { }); } - public void testNonMethodParameterLists() { - withLevel(LanguageLevel.JDK_1_7, new Runnable() { - @Override public void run() { - doTest("class C {\n" + - " {\n" + - " try (Resource r = new Resource()) { }\n" + - " }\n" + - "}", - - "PsiJavaFileStub []\n" + - " IMPORT_LIST:PsiImportListStub\n" + - " CLASS:PsiClassStub[name=C fqn=C]\n" + - " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + - " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + - " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + - " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + - " CLASS_INITIALIZER:PsiClassInitializerStub\n" + - " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n"); - } - }); - } - public void testSOEProof() { final StringBuilder sb = new StringBuilder(); final SecureRandom random = new SecureRandom(); diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBracesTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBracesTest.java index 823218a86e1c..a1ba7ff3bd7a 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBracesTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBracesTest.java @@ -113,4 +113,23 @@ public class JavaFormatterBracesTest extends AbstractJavaFormatterTest { "}" ); } + + public void testKeepSimpleClassesAndInterfacesInOneLine() { + // Inspired by IDEA-65433 + getSettings().KEEP_SIMPLE_CLASSES_IN_ONE_LINE = true; + + String[] tests = { + "class Test {}", + "interface Test {}", + "class Test {\n" + + " void test() {\n" + + " new Object() {};\n" + + " }\n" + + "}" + }; + + for (String test : tests) { + doTextTest(test, test); + } + } } diff --git a/java/openapi/src/com/intellij/pom/java/events/PomJavaAspectChangeSet.java b/java/openapi/src/com/intellij/pom/java/events/PomJavaAspectChangeSet.java index d1e2792219f9..ebbd94c2d4e2 100644 --- a/java/openapi/src/com/intellij/pom/java/events/PomJavaAspectChangeSet.java +++ b/java/openapi/src/com/intellij/pom/java/events/PomJavaAspectChangeSet.java @@ -20,7 +20,7 @@ import com.intellij.pom.PomModel; import com.intellij.pom.PomModelAspect; import com.intellij.pom.event.PomChangeSet; import com.intellij.pom.java.PomJavaAspect; -import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -28,33 +28,24 @@ import java.util.List; public class PomJavaAspectChangeSet implements PomChangeSet{ private final PomModel myModel; private final List myChanges = new ArrayList(); - private final PsiFile myChangedFile; - public PomJavaAspectChangeSet(PomModel model, PsiFile fileChanged) { + public PomJavaAspectChangeSet(PomModel model) { myModel = model; - myChangedFile = fileChanged; } public void addChange(PomJavaChange change) { myChanges.add(change); } - public List getChanges() { - return myChanges; - } - + @NotNull public PomModelAspect getAspect() { return myModel.getModelAspect(PomJavaAspect.class); } - public void merge(PomChangeSet blocked) { + public void merge(@NotNull PomChangeSet blocked) { if(!(blocked instanceof PomJavaAspectChangeSet)) return; final PomJavaAspectChangeSet blockedJavaChange = (PomJavaAspectChangeSet)blocked; myChanges.addAll(blockedJavaChange.myChanges); } - - public PsiFile getChangedFile() { - return myChangedFile; - } } diff --git a/java/openapi/src/com/intellij/psi/JavaElementVisitor.java b/java/openapi/src/com/intellij/psi/JavaElementVisitor.java index 810755020371..c8162c6004b3 100644 --- a/java/openapi/src/com/intellij/psi/JavaElementVisitor.java +++ b/java/openapi/src/com/intellij/psi/JavaElementVisitor.java @@ -238,7 +238,7 @@ public abstract class JavaElementVisitor extends PsiElementVisitor { * of this method we can easily stuck with exponential algorithm if the derived visitor * extends visitElement() and accepts children there. * PsiRecursiveElement visitor works that around and implements this method accordingly. - * All other visitor must decide themselves what implementation (visitReferenceElement() or visitExpreission() or none or LOG.error()) + * All other visitor must decide themselves what implementation (visitReferenceElement() or visitExpression() or none or LOG.error()) * is appropriate for them. * @param expression */ @@ -296,6 +296,14 @@ public abstract class JavaElementVisitor extends PsiElementVisitor { visitElement(section); } + public void visitResourceList(PsiResourceList resourceList) { + visitElement(resourceList); + } + + public void visitResource(PsiResource resource) { + visitElement(resource); + } + public void visitTypeElement(PsiTypeElement type) { visitElement(type); } diff --git a/java/openapi/src/com/intellij/psi/PsiDiamondType.java b/java/openapi/src/com/intellij/psi/PsiDiamondType.java index 926fbd99ef6b..5b1488918a12 100644 --- a/java/openapi/src/com/intellij/psi/PsiDiamondType.java +++ b/java/openapi/src/com/intellij/psi/PsiDiamondType.java @@ -16,15 +16,20 @@ package com.intellij.psi; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.*; + /** * User: anna * Date: Jul 30, 2010 @@ -82,152 +87,260 @@ public class PsiDiamondType extends PsiType { return new PsiType[]{getJavaLangObject(myManager, getResolveScope())}; } - public PsiType[] getInferredTypes() { - final PsiDeclarationStatement declarationStatement = PsiTreeUtil.getParentOfType(myTypeElement, PsiDeclarationStatement.class); - if (declarationStatement != null) { - final PsiElement[] declaredElements = declarationStatement.getDeclaredElements(); - if (declaredElements.length > 0 && declaredElements[0] instanceof PsiVariable) { - return getComponentTypes((PsiVariable)declaredElements[0]); - } + public DiamondInferenceResult resolveInferredTypes() { + final PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(myTypeElement, PsiNewExpression.class); + if (newExpression == null) { + return PsiDiamondType.DiamondInferenceResult.NULL_RESULT; } - final PsiAssignmentExpression assignmentExpression = PsiTreeUtil.getParentOfType(myTypeElement, PsiAssignmentExpression.class); - if (assignmentExpression != null) { - final PsiExpression lExpression = assignmentExpression.getLExpression(); - if (lExpression instanceof PsiReferenceExpression) { - final PsiElement resolved = ((PsiReferenceExpression)lExpression).resolve(); - if (resolved instanceof PsiVariable) { - return getComponentTypes(((PsiVariable)resolved)); - } - } - } - - PsiExpression psiExpression = PsiTreeUtil.getParentOfType(myTypeElement, PsiExpression.class); - while (psiExpression != null) { - final PsiElement parent = psiExpression.getParent(); - if (parent instanceof PsiExpression) { - psiExpression = (PsiExpression)parent; - continue; - } - break; - } - if (psiExpression != null) { - final PsiElement parent = psiExpression.getParent(); - if (parent instanceof PsiExpressionList) { - final PsiElement parentParent = parent.getParent(); - if (parentParent instanceof PsiCallExpression) { - final JavaResolveResult resolveResult = ((PsiCallExpression)parentParent).resolveMethodGenerics(); - final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); - final PsiElement element = resolveResult.getElement(); - if (element instanceof PsiMethod) { - final int paramIdx = ArrayUtil.find(((PsiExpressionList)parent).getExpressions(), psiExpression); - if (paramIdx > -1) { - final PsiParameter parameter = - ((PsiMethod)element).getParameterList().getParameters()[paramIdx]; - return getComponentTypes(substitutor.substitute(parameter.getType())); - } - } - } - } else if (parent instanceof PsiVariable) { - return getComponentTypes((PsiVariable)parent); - } else if (parent instanceof PsiReturnStatement) { - final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(parent, PsiMethod.class); - if (containingMethod != null) { - final PsiType returnType = containingMethod.getReturnType(); - if (returnType != null) { - final PsiExpression returnValue = ((PsiReturnStatement)parent).getReturnValue(); - if (returnValue instanceof PsiNewExpression) { - return getComponentTypes(returnType, returnValue); - } - return getComponentTypes(returnType); - } - } - } - } - return NULL_TYPES; + return resolveInferredTypes(newExpression); } - private static PsiType[] getComponentTypes(PsiVariable declaredElement) { - final PsiType lType = declaredElement.getType(); - final PsiExpression initializer = declaredElement.getInitializer(); - return getComponentTypes(lType, initializer); - } - - private static PsiType[] getComponentTypes(PsiType lType, PsiExpression initializer) { - if (initializer instanceof PsiNewExpression) { - final PsiNewExpression newExpression = (PsiNewExpression)initializer; - final PsiJavaCodeReferenceElement classReference = newExpression.getClassOrAnonymousClassReference(); - if (classReference != null) { - final String text = classReference.getReferenceName(); - if (text != null) { - final PsiClass psiClass = - JavaPsiFacade.getInstance(initializer.getProject()).getResolveHelper().resolveReferencedClass(text, initializer); - final PsiType substitute = substitute(psiClass, lType); - if (substitute != null) { - lType = substitute; - } + public static DiamondInferenceResult resolveInferredTypes(PsiNewExpression newExpression) { + final PsiClass psiClass = findClass(newExpression); + if (psiClass == null) return DiamondInferenceResult.NULL_RESULT; + final PsiExpressionList argumentList = newExpression.getArgumentList(); + if (argumentList == null) return DiamondInferenceResult.NULL_RESULT; + final PsiMethod constructor = findConstructor(psiClass, newExpression); + PsiTypeParameter[] params = getAllTypeParams(constructor, psiClass); + PsiMethod staticFactory = generateStaticFactory(constructor, psiClass, params); + if (staticFactory == null) { + return DiamondInferenceResult.NULL_RESULT; + } + final PsiSubstitutor inferredSubstitutor = inferTypeParametersForStaticFactory(staticFactory, newExpression); + final PsiTypeParameter[] parameters = staticFactory.getTypeParameters(); + final PsiTypeParameter[] classParameters = psiClass.getTypeParameters(); + final PsiJavaCodeReferenceElement classOrAnonymousClassReference = newExpression.getClassOrAnonymousClassReference(); + LOG.assertTrue(classOrAnonymousClassReference != null); + final DiamondInferenceResult result = new DiamondInferenceResult(classOrAnonymousClassReference.getReferenceName() + "<>"); + for (PsiTypeParameter parameter : parameters) { + for (PsiTypeParameter classParameter : classParameters) { + if (Comparing.strEqual(classParameter.getName(), parameter.getName())) { + result.addInferredType(inferredSubstitutor.substitute(parameter)); + break; } } } - return getComponentTypes(lType); + return result; + } + + + @Nullable + private static PsiMethod findConstructor(PsiClass containingClass, PsiNewExpression newExpression) { + final PsiExpressionList argumentList = newExpression.getArgumentList(); + final Project project = newExpression.getProject(); + final JavaPsiFacade facade = JavaPsiFacade.getInstance(project); + final PsiResolveHelper resolveHelper = facade.getResolveHelper(); + final JavaResolveResult result = + resolveHelper.resolveConstructor(facade.getElementFactory().createType(containingClass), argumentList, argumentList); + return (PsiMethod)result.getElement(); } @Nullable - private static PsiType substitute(PsiClass inheritor, PsiType baseType) { - if (inheritor == null) return null; - final JavaPsiFacade facade = JavaPsiFacade.getInstance(inheritor.getProject()); - final PsiResolveHelper resolveHelper = facade.getResolveHelper(); - final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(baseType); - final PsiClass baseClass = resolveResult.getElement(); - if (baseClass == null) return null; - - PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(baseClass, inheritor, PsiSubstitutor.EMPTY); - if (superSubstitutor == null) return null; - - final PsiSubstitutor baseSubstitutor = resolveResult.getSubstitutor(); - - PsiSubstitutor inheritorSubstitutor = PsiSubstitutor.EMPTY; - for (PsiTypeParameter inheritorParameter : PsiUtil.typeParametersIterable(inheritor)) { - for (PsiTypeParameter baseParameter : PsiUtil.typeParametersIterable(baseClass)) { - final PsiType substituted = superSubstitutor.substitute(baseParameter); - PsiType arg = baseSubstitutor.substitute(baseParameter); - if (arg instanceof PsiWildcardType) arg = ((PsiWildcardType)arg).getExtendsBound(); - PsiType substitution = resolveHelper.getSubstitutionForTypeParameter(inheritorParameter, - substituted, - arg, - true, - PsiUtil.getLanguageLevel(inheritor)); - if (PsiType.NULL.equals(substitution) || substitution instanceof PsiWildcardType) continue; - if (substitution == null) { - continue; - } - inheritorSubstitutor = inheritorSubstitutor.put(inheritorParameter, substitution); - break; + private static PsiClass findClass(PsiNewExpression newExpression) { + final PsiJavaCodeReferenceElement classReference = newExpression.getClassOrAnonymousClassReference(); + if (classReference != null) { + final String text = classReference.getReferenceName(); + if (text != null) { + final Project project = newExpression.getProject(); + final JavaPsiFacade facade = JavaPsiFacade.getInstance(project); + final PsiResolveHelper resolveHelper = facade.getResolveHelper(); + return resolveHelper.resolveReferencedClass(text, newExpression); + } else { + return null; } } - - PsiType toAdd = facade.getElementFactory().createType(inheritor, inheritorSubstitutor); - if (baseType.isAssignableFrom(toAdd)) { - return toAdd; - } - return null; } - private static PsiType[] getComponentTypes(PsiType type) { - if (type instanceof PsiClassType) { - final PsiType[] types = ((PsiClassType)type).getParameters(); - for (int i = 0; i < types.length; i++) { - PsiType currentType = types[i]; - if (currentType instanceof PsiWildcardType) { - final PsiType bound = ((PsiWildcardType)currentType).getBound(); - if (bound != null) { - types[i] = bound; - } - } + @Nullable + private static PsiMethod generateStaticFactory(@Nullable PsiMethod constructor, PsiClass containingClass, PsiTypeParameter[] params) { + final StringBuilder buf = new StringBuilder(); + buf.append("public static "); + buf.append("<"); + buf.append(StringUtil.join(params, new Function() { + @Override + public String fun(PsiTypeParameter psiTypeParameter) { + return psiTypeParameter.getName(); } - return types; + }, ", ")); + buf.append(">"); + + final String qualifiedName = containingClass.getQualifiedName(); + buf.append(qualifiedName != null ? qualifiedName : containingClass.getName()); + final PsiTypeParameter[] parameters = containingClass.getTypeParameters(); + buf.append("<"); + buf.append(StringUtil.join(parameters, new Function() { + @Override + public String fun(PsiTypeParameter psiTypeParameter) { + return psiTypeParameter.getName(); + } + }, ", ")); + buf.append("> "); + + String staticFactoryName = "staticFactory"; + final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(containingClass.getProject()); + staticFactoryName = styleManager.suggestUniqueVariableName(staticFactoryName, containingClass, false); + buf.append(staticFactoryName); + if (constructor == null) { + buf.append("()"); } - return NULL_TYPES; + else { + buf.append("(").append(StringUtil.join(constructor.getParameterList().getParameters(), new Function() { + @Override + public String fun(PsiParameter psiParameter) { + return psiParameter.getType().getCanonicalText() + " " + psiParameter.getName(); + } + }, ",")).append(")"); + } + buf.append("{}"); + + return JavaPsiFacade.getElementFactory(containingClass.getProject()).createMethodFromText(buf.toString(), constructor != null ? constructor : containingClass); + } + + private static PsiTypeParameter[] getAllTypeParams(PsiTypeParameterListOwner listOwner, PsiClass containingClass) { + Set params = new LinkedHashSet(); + if (listOwner != null) { + Collections.addAll(params, listOwner.getTypeParameters()); + } + Collections.addAll(params, containingClass.getTypeParameters()); + return params.toArray(new PsiTypeParameter[params.size()]); + } + + + private static PsiSubstitutor inferTypeParametersForStaticFactory(@NotNull PsiMethod staticFactoryMethod, + PsiNewExpression expression) { + final JavaPsiFacade facade = JavaPsiFacade.getInstance(staticFactoryMethod.getProject()); + final PsiResolveHelper resolveHelper = facade.getResolveHelper(); + final PsiParameter[] parameters = staticFactoryMethod.getParameterList().getParameters(); + final PsiExpressionList argumentList = expression.getArgumentList(); + final PsiExpression[] expressions = argumentList.getExpressions(); + return resolveHelper + .inferTypeArguments(staticFactoryMethod.getTypeParameters(), parameters, expressions, PsiSubstitutor.EMPTY, expression, false); + } + + public static class DiamondInferenceResult { + public static final DiamondInferenceResult NULL_RESULT = new DiamondInferenceResult() { + @Override + public PsiType[] getTypes() { + return NULL_TYPES; + } + + @Override + public String getErrorMessage() { + return "Cannot infer arguments"; + } + }; + + private List myInferredTypes = new ArrayList(); + private String myErrorMessage; + + private String myNewExpressionPresentableText; + + public DiamondInferenceResult() { + } + + public DiamondInferenceResult(String expressionPresentableText) { + myNewExpressionPresentableText = expressionPresentableText; + } + + public PsiType[] getTypes() { + if (myErrorMessage != null) { + return NULL_TYPES; + } + return myInferredTypes.toArray(new PsiType[myInferredTypes.size()]); + } + + public String getErrorMessage() { + return myErrorMessage; + } + + public void addInferredType(PsiType psiType) { + if (myErrorMessage != null) return; + if (psiType == null) { + myErrorMessage = "Cannot infer type arguments for " + myNewExpressionPresentableText; + } else if (!isValid(psiType)) { + myErrorMessage = "Cannot infer type arguments for " + + myNewExpressionPresentableText + " because type " + psiType.getPresentableText() + " inferred is not allowed in current context"; + } else { + myInferredTypes.add(psiType); + } + } + + private static Boolean isValid(PsiType type) { + return type.accept(new PsiTypeVisitor() { + @Override + public Boolean visitType(PsiType type) { + return !(type instanceof PsiIntersectionType); + } + + @Override + public Boolean visitCapturedWildcardType(PsiCapturedWildcardType capturedWildcardType) { + return false; + } + + @Override + public Boolean visitWildcardType(PsiWildcardType wildcardType) { + final PsiType bound = wildcardType.getBound(); + if (bound != null) { + if (bound instanceof PsiIntersectionType) return false; + return bound.accept(this); + } + return true; + } + + @Override + public Boolean visitClassType(PsiClassType classType) { + for (PsiType psiType : classType.getParameters()) { + if (!psiType.accept(this)) { + return false; + } + } + return true; + } + }); + } + } + + public static boolean hasDefaultConstructor(@NotNull final PsiClass psiClass) { + final PsiMethod[] constructors = psiClass.getConstructors(); + for (PsiMethod method : constructors) { + if (method.getParameterList().getParametersCount() == 0) return true; + } + return constructors.length == 0; + } + + public static boolean haveConstructorsGenericsParameters(@NotNull final PsiClass psiClass) { + for (PsiMethod method : psiClass.getConstructors()) { + for (PsiParameter parameter : method.getParameterList().getParameters()) { + final PsiType type = parameter.getType(); + final Boolean accept = type.accept(new PsiTypeVisitor() { + @Override + public Boolean visitArrayType(PsiArrayType arrayType) { + return arrayType.getComponentType().accept(this); + } + + @Override + public Boolean visitClassType(PsiClassType classType) { + for (PsiType psiType : classType.getParameters()) { + if (psiType != null) { + final Boolean typaParamFound = psiType.accept(this); + if (typaParamFound != null && typaParamFound) return true; + } + } + return PsiUtil.resolveClassInType(classType) instanceof PsiTypeParameter; + } + + @Override + public Boolean visitWildcardType(PsiWildcardType wildcardType) { + final PsiType bound = wildcardType.getBound(); + if (bound == null) return false; + return bound.accept(this); + } + }); + if (accept != null && accept.booleanValue()) return true; + } + } + return false; } } diff --git a/java/openapi/src/com/intellij/psi/PsiDisjunctionType.java b/java/openapi/src/com/intellij/psi/PsiDisjunctionType.java index 0ae89e9850b4..8b4b4bace061 100644 --- a/java/openapi/src/com/intellij/psi/PsiDisjunctionType.java +++ b/java/openapi/src/com/intellij/psi/PsiDisjunctionType.java @@ -30,8 +30,8 @@ import java.util.Collections; import java.util.List; /** - * Composite type resulting from Project Coin's multi-catch statements, * i.e. FileNotFoundException | EOFException. - * In most cases should be threatened via its least upper bound * (IOException in the example above). + * Composite type resulting from Project Coin's multi-catch statements, i.e. FileNotFoundException | EOFException. + * In most cases should be threatened via its least upper bound (IOException in the example above). */ public class PsiDisjunctionType extends PsiType { private final PsiManager myManager; @@ -64,8 +64,8 @@ public class PsiDisjunctionType extends PsiType { return myTypes; } - public PsiManager getManager() { - return myManager; + public PsiDisjunctionType newDisjunctionType(final List types) { + return new PsiDisjunctionType(types, myManager); } @Override diff --git a/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java b/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java index 3d9e0307f916..6e59d5430e38 100644 --- a/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java +++ b/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java @@ -116,6 +116,17 @@ public interface PsiJavaParserFacade extends PsiParserFacade { @NotNull PsiParameter createParameterFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + /** + * Creates a Java try-resource from the specified text. + * + * @param text the text of the resource to create. + * @param context the PSI element used as context for resolving references from the resource. + * @return the created resource instance. + * @throws com.intellij.util.IncorrectOperationException if the text is not a valid resource definition. + */ + @NotNull + PsiResource createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException; + /** * Creates a Java type from the specified text. * diff --git a/java/openapi/src/com/intellij/psi/PsiResource.java b/java/openapi/src/com/intellij/psi/PsiResource.java new file mode 100644 index 000000000000..e53289079c86 --- /dev/null +++ b/java/openapi/src/com/intellij/psi/PsiResource.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2011 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.psi; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Represents a resource list of try-with-resources statement (automatic resource management) introduced in JDK 7. + * + * @see PsiResourceList#getResources() + * @since 10.5. + */ +public interface PsiResource extends PsiElement { + /** + * Returns main element of the resource. + * It may be PsiLocalVariable, PsiAssignmentExpression, or other instance of PsiExpression. + * + * @return resource element. + */ + @NotNull + PsiElement getResourceElement(); + + @Nullable + PsiType getType(); +} diff --git a/java/openapi/src/com/intellij/psi/PsiResourceList.java b/java/openapi/src/com/intellij/psi/PsiResourceList.java new file mode 100644 index 000000000000..c954ae7e79bd --- /dev/null +++ b/java/openapi/src/com/intellij/psi/PsiResourceList.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2011 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.psi; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Represents a resource list of try-with-resources statement (automatic resource management) introduced in JDK 7. + * + * @see PsiTryStatement#getResourceList() + * @since 10.5. + */ +public interface PsiResourceList extends PsiElement { + @NotNull + List getResources(); +} diff --git a/java/openapi/src/com/intellij/psi/PsiScopedLocalVariable.java b/java/openapi/src/com/intellij/psi/PsiScopedLocalVariable.java new file mode 100644 index 000000000000..b6f74359b683 --- /dev/null +++ b/java/openapi/src/com/intellij/psi/PsiScopedLocalVariable.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2011 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.psi; + +import org.jetbrains.annotations.NotNull; + +public interface PsiScopedLocalVariable extends PsiLocalVariable { + /** + * Returns the element or elements (method, "for" statement or try block) in which the variable is declared. + * + * @return the declaration scope for the variable. + */ + @NotNull + PsiElement[] getDeclarationScope(); +} diff --git a/java/openapi/src/com/intellij/psi/PsiTryStatement.java b/java/openapi/src/com/intellij/psi/PsiTryStatement.java index 91375d343340..dd5574b5d322 100644 --- a/java/openapi/src/com/intellij/psi/PsiTryStatement.java +++ b/java/openapi/src/com/intellij/psi/PsiTryStatement.java @@ -71,5 +71,5 @@ public interface PsiTryStatement extends PsiStatement { * @return resource list, or null if the statement doesn't have it. */ @Nullable - PsiParameterList getResourceList(); + PsiResourceList getResourceList(); } diff --git a/java/openapi/src/com/intellij/psi/util/PsiUtil.java b/java/openapi/src/com/intellij/psi/util/PsiUtil.java index f34dfee9b11d..12f0b759f1f8 100644 --- a/java/openapi/src/com/intellij/psi/util/PsiUtil.java +++ b/java/openapi/src/com/intellij/psi/util/PsiUtil.java @@ -635,7 +635,6 @@ public final class PsiUtil extends PsiUtilBase { return PsiTreeUtil.getParentOfType(element, PsiDocComment.class, true) != null; } - private static class ParamWriteProcessor implements Processor { private volatile boolean myIsWriteRefFound = false; public boolean process(PsiReference reference) { @@ -651,6 +650,7 @@ public final class PsiUtil extends PsiUtilBase { return myIsWriteRefFound; } } + public static boolean isAssigned(final PsiParameter parameter) { ParamWriteProcessor processor = new ParamWriteProcessor(); ReferencesSearch.search(parameter, new LocalSearchScope(parameter.getDeclarationScope()), true).forEach(processor); @@ -717,7 +717,7 @@ public final class PsiUtil extends PsiUtilBase { } } - /** + /* * Returns iterator of type parameters visible in owner. Type parameters are iterated in * inner-to-outer, right-to-left order. */ diff --git a/java/openapi/src/com/intellij/psi/util/TypeConversionUtil.java b/java/openapi/src/com/intellij/psi/util/TypeConversionUtil.java index bbe345501d62..295a4a03a585 100644 --- a/java/openapi/src/com/intellij/psi/util/TypeConversionUtil.java +++ b/java/openapi/src/com/intellij/psi/util/TypeConversionUtil.java @@ -1170,7 +1170,7 @@ public class TypeConversionUtil { final List erased = ContainerUtil.map(disjunctionType.getDisjunctions(), new Function() { @Override public PsiType fun(PsiType psiType) { return erasure(psiType, beforeSubstitutor); } }); - return new PsiDisjunctionType(erased, disjunctionType.getManager()); + return disjunctionType.newDisjunctionType(erased); } }); } diff --git a/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java b/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java index cbe0eb8c9a30..c1c6510b24d3 100644 --- a/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java +++ b/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java @@ -25,8 +25,6 @@ import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.ide.util.treeView.*; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.project.DumbAwareRunnable; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.Queryable; import com.intellij.openapi.util.Disposer; @@ -300,4 +298,9 @@ public abstract class BaseProjectViewTestCase extends TestSourceBasedTestCase { protected String getTestDataPath() { return PathManagerEx.getTestDataPath(getClass()); } + + @Override + protected boolean isRunInWriteAction() { + return false; + } } diff --git a/native/restarter/.gitignore b/native/restarter/.gitignore new file mode 100644 index 000000000000..5f88d71148d0 --- /dev/null +++ b/native/restarter/.gitignore @@ -0,0 +1,8 @@ +Debug +Release +_UpgradeReport_Files +*.suo +*.vcxproj.user +UpgradeLog.xml +ipch +*.sdf diff --git a/platform/lang-api/src/com/intellij/analysis/AnalysisScope.java b/platform/lang-api/src/com/intellij/analysis/AnalysisScope.java index 9460a5791b6b..b7fc38cdbc95 100644 --- a/platform/lang-api/src/com/intellij/analysis/AnalysisScope.java +++ b/platform/lang-api/src/com/intellij/analysis/AnalysisScope.java @@ -237,7 +237,9 @@ public class AnalysisScope { protected void accept(final PsiElementVisitor visitor, final boolean needReadAction) { if (myType == VIRTUAL_FILES) { final PsiManager psiManager = PsiManager.getInstance(myProject); + final FileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex(); for (final VirtualFile file : myFilesSet) { + if (!myIncludeTestSource && index.isInTestSourceContent(file)) continue; if (!processFile(file, visitor, psiManager, needReadAction)) return; } } else if (myScope instanceof GlobalSearchScope) { @@ -247,6 +249,7 @@ public class AnalysisScope { public boolean processFile(final VirtualFile fileOrDir) { final boolean isInScope = ApplicationManager.getApplication().runReadAction(new Computable() { public Boolean compute() { + if (!myIncludeTestSource && projectFileIndex.isInTestSourceContent(fileOrDir)) return false; return ((GlobalSearchScope)myScope).contains(fileOrDir); } }).booleanValue(); diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/AbstractCompletionContributor.java b/platform/lang-api/src/com/intellij/codeInsight/completion/AbstractCompletionContributor.java deleted file mode 100644 index 649b0ed437b7..000000000000 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/AbstractCompletionContributor.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.completion; - -/** - * @author peter - */ -public abstract class AbstractCompletionContributor { - - /** - * Fill completion variants. - * - * Invoked sequentially for all registered contributors in order of registration. - * - * @param parameters - * @param result - * @return Whether to continue variants collecting process. If false, remaining non-visited completion contributors are ignored. - * @see CompletionService#getVariantsFromContributors(com.intellij.openapi.extensions.ExtensionPointName, CompletionParameters, AbstractCompletionContributor , com.intellij.util.Consumer) - */ - public abstract void fillCompletionVariants(Params parameters, CompletionResultSet result); -} diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java index 9ad079f101ee..9e0a43281237 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java @@ -125,7 +125,7 @@ import java.util.List; * * @author peter */ -public abstract class CompletionContributor extends AbstractCompletionContributor{ +public abstract class CompletionContributor { private final MultiMap, CompletionProvider>> myMap = new MultiMap, CompletionProvider>>(); diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionSorter.java b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionSorter.java index b5532add33d3..fd63710141b6 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionSorter.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionSorter.java @@ -22,9 +22,9 @@ import org.jetbrains.annotations.NotNull; * @author peter */ public abstract class CompletionSorter { - public abstract CompletionSorter weighBefore(@NotNull String beforeId, LookupElementWeigher weigher); + public abstract CompletionSorter weighBefore(@NotNull String beforeId, LookupElementWeigher... weighers); - public abstract CompletionSorter weighAfter(@NotNull String afterId, LookupElementWeigher weigher); + public abstract CompletionSorter weighAfter(@NotNull String afterId, LookupElementWeigher... weighers); public abstract CompletionSorter weigh(LookupElementWeigher weigher); diff --git a/java/execution/openapi/src/com/intellij/execution/configurations/RefactoringListenerProvider.java b/platform/lang-api/src/com/intellij/execution/configurations/RefactoringListenerProvider.java similarity index 100% rename from java/execution/openapi/src/com/intellij/execution/configurations/RefactoringListenerProvider.java rename to platform/lang-api/src/com/intellij/execution/configurations/RefactoringListenerProvider.java diff --git a/platform/lang-api/src/com/intellij/lang/LanguageDocumentation.java b/platform/lang-api/src/com/intellij/lang/LanguageDocumentation.java index ddd0c5cca6f0..130a63b34452 100644 --- a/platform/lang-api/src/com/intellij/lang/LanguageDocumentation.java +++ b/platform/lang-api/src/com/intellij/lang/LanguageDocumentation.java @@ -21,6 +21,7 @@ package com.intellij.lang; import com.intellij.lang.documentation.CompositeDocumentationProvider; import com.intellij.lang.documentation.DocumentationProvider; +import org.jetbrains.annotations.NonNls; import java.util.List; diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java index 4ec1419fbd46..cf0259da26e8 100644 --- a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java @@ -38,6 +38,7 @@ import org.jetbrains.annotations.Nullable; import java.io.*; import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; import java.util.Map; import java.util.jar.Attributes; import java.util.jar.JarFile; @@ -146,11 +147,23 @@ public class JdkUtil { commandLine.setExePath(exePath); ParametersList parametersList = javaParameters.getVMParametersList(); commandLine.addParameters(parametersList.getList()); - if (!parametersList.hasProperty("file.encoding")) { + + // Value of -Dfile.encoding and charset of GeneralCommandLine should be in sync in order process's input and output be correctly handled. + String encoding = parametersList.getPropertyValue("file.encoding"); + if (encoding == null) { Charset charset = javaParameters.getCharset(); if (charset == null) charset = EncodingManager.getInstance().getDefaultCharset(); if (charset == null) charset = CharsetToolkit.getDefaultSystemCharset(); - commandLine.setCharsetAndAddJavaParameter(charset); + commandLine.addParameter("-Dfile.encoding=" + charset.name()); + commandLine.setCharset(charset); + } + else { + try { + Charset charset = Charset.forName(encoding); + commandLine.setCharset(charset); + } + catch (UnsupportedCharsetException ignore) { + } } final Map env = javaParameters.getEnv(); diff --git a/platform/lang-api/src/com/intellij/pom/event/PomChangeSet.java b/platform/lang-api/src/com/intellij/pom/event/PomChangeSet.java index 37315a0aed40..c2247b97c9dc 100644 --- a/platform/lang-api/src/com/intellij/pom/event/PomChangeSet.java +++ b/platform/lang-api/src/com/intellij/pom/event/PomChangeSet.java @@ -16,8 +16,10 @@ package com.intellij.pom.event; import com.intellij.pom.PomModelAspect; +import org.jetbrains.annotations.NotNull; public interface PomChangeSet { + @NotNull PomModelAspect getAspect(); - void merge(PomChangeSet blocked); + void merge(@NotNull PomChangeSet blocked); } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/pom/event/PomModelEvent.java b/platform/lang-api/src/com/intellij/pom/event/PomModelEvent.java index 2697ed849cd6..e5387834deba 100644 --- a/platform/lang-api/src/com/intellij/pom/event/PomModelEvent.java +++ b/platform/lang-api/src/com/intellij/pom/event/PomModelEvent.java @@ -43,11 +43,11 @@ public class PomModelEvent extends EventObject { if (myChangeSets == null) { myChangeSets = new HashMap(); } - if (set != null) { - myChangeSets.put(aspect, set); + if (set == null) { + myChangeSets.remove(aspect); } else { - myChangeSets.remove(aspect); + myChangeSets.put(aspect, set); } } diff --git a/platform/lang-api/src/com/intellij/pom/tree/TreeAspect.java b/platform/lang-api/src/com/intellij/pom/tree/TreeAspect.java index da5bcc28cb8d..16334758f3e7 100644 --- a/platform/lang-api/src/com/intellij/pom/tree/TreeAspect.java +++ b/platform/lang-api/src/com/intellij/pom/tree/TreeAspect.java @@ -18,13 +18,12 @@ package com.intellij.pom.tree; import com.intellij.pom.PomModel; import com.intellij.pom.PomModelAspect; import com.intellij.pom.event.PomModelEvent; +import org.jetbrains.annotations.NotNull; import java.util.Collections; -import org.jetbrains.annotations.NotNull; - public class TreeAspect implements PomModelAspect{ - public TreeAspect(PomModel model) { + public TreeAspect(@NotNull PomModel model) { model.registerAspect(TreeAspect.class, this, Collections.emptySet()); } diff --git a/platform/lang-api/src/com/intellij/pom/tree/events/TreeChangeEvent.java b/platform/lang-api/src/com/intellij/pom/tree/events/TreeChangeEvent.java index 4485fe63e7ff..7520514dfe88 100644 --- a/platform/lang-api/src/com/intellij/pom/tree/events/TreeChangeEvent.java +++ b/platform/lang-api/src/com/intellij/pom/tree/events/TreeChangeEvent.java @@ -17,18 +17,21 @@ package com.intellij.pom.tree.events; import com.intellij.lang.ASTNode; import com.intellij.pom.event.PomChangeSet; +import org.jetbrains.annotations.NotNull; /** * @author ik */ public interface TreeChangeEvent extends PomChangeSet { + @NotNull ASTNode getRootElement(); + @NotNull ASTNode[] getChangedElements(); - TreeChange getChangesByElement(ASTNode element); + TreeChange getChangesByElement(@NotNull ASTNode element); - void addElementaryChange(ASTNode child, ChangeInfo change); + void addElementaryChange(@NotNull ASTNode child, @NotNull ChangeInfo change); void clear(); } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java index 4c0055ceb905..e79ff8eedfc3 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java @@ -216,4 +216,20 @@ public abstract class CodeStyleManager { * the file is read-only). */ public abstract void reformatNewlyAddedElement(@NotNull final ASTNode block, @NotNull final ASTNode addedElement) throws IncorrectOperationException; + + /** + * Formatting may be executed sequentially, i.e. the whole (re)formatting task is split into a number of smaller sub-tasks + * that are executed sequentially. That is done primarily for ability to show progress dialog during formatting (formatting + * is always performed from EDT, hence, the GUI freezes if we perform formatting as a single big iteration). + *

+ * However, there are situation when we don't want to use such an approach - for example, IntelliJ IDEA sometimes inserts dummy + * text into file in order to calculate formatting-specific data and removes it after that. We don't want to allow Swing events + * dispatching during that in order to not show that dummy text to the end-user. + *

+ * It's possible to configure that (implementation details are insignificant here) and current method serves as a read-only + * facade for obtaining information if 'sequential' processing is allowed at the moment. + * + * @return true if 'sequential' formatting is allowed now; false otherwise + */ + public abstract boolean isSequentialProcessingAllowed(); } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java index 5ac8f5bd2a22..5bd8c3d1854a 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java @@ -654,6 +654,7 @@ public class CommonCodeStyleSettings { public boolean KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = false; public boolean KEEP_SIMPLE_METHODS_IN_ONE_LINE = false; + public boolean KEEP_SIMPLE_CLASSES_IN_ONE_LINE = false; public boolean KEEP_MULTIPLE_EXPRESSIONS_IN_ONE_LINE = false; public int FOR_STATEMENT_WRAP = DO_NOT_WRAP; diff --git a/platform/lang-api/src/com/intellij/refactoring/listeners/RefactoringElementAdapter.java b/platform/lang-api/src/com/intellij/refactoring/listeners/RefactoringElementAdapter.java new file mode 100644 index 000000000000..11cba838d421 --- /dev/null +++ b/platform/lang-api/src/com/intellij/refactoring/listeners/RefactoringElementAdapter.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2011 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.refactoring.listeners; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +/** + * @author yole + */ +public abstract class RefactoringElementAdapter implements RefactoringElementListener { + @Override + public final void elementMoved(@NotNull PsiElement newElement) { + elementRenamedOrMoved(newElement); + } + + protected abstract void elementRenamedOrMoved(@NotNull PsiElement newElement); + + @Override + public final void elementRenamed(@NotNull PsiElement newElement) { + elementRenamedOrMoved(newElement); + } +} diff --git a/platform/lang-api/src/com/intellij/util/indexing/ID.java b/platform/lang-api/src/com/intellij/util/indexing/ID.java index e400793c745c..463fcaee4276 100644 --- a/platform/lang-api/src/com/intellij/util/indexing/ID.java +++ b/platform/lang-api/src/com/intellij/util/indexing/ID.java @@ -78,6 +78,8 @@ public class ID { } int n = ourNameToIdRegistry.size() + 1; + assert n <= Short.MAX_VALUE : "Number of indices exceeded"; + ourNameToIdRegistry.put(name, n); writeEnumFile(); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java index f71cb326b960..9cbf44d54ae7 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java @@ -35,8 +35,10 @@ public class WrappingAndBracesPanel extends OptionTableWithPreviewPanel { addOption("KEEP_FIRST_COLUMN_COMMENT", ApplicationBundle.message("wrapping.keep.comment.at.first.column"), WRAPPING_KEEP); addOption("KEEP_CONTROL_STATEMENT_IN_ONE_LINE", ApplicationBundle.message("checkbox.keep.when.reformatting.control.statement.in.one.line"), WRAPPING_KEEP); - addOption("KEEP_SIMPLE_BLOCKS_IN_ONE_LINE", ApplicationBundle.message("wrapping.keep.simple.blocks.in.one.line"), WRAPPING_KEEP); addOption("KEEP_MULTIPLE_EXPRESSIONS_IN_ONE_LINE", ApplicationBundle.message("wrapping.keep.multiple.expressions.in.one.line"), WRAPPING_KEEP); + addOption("KEEP_SIMPLE_BLOCKS_IN_ONE_LINE", ApplicationBundle.message("wrapping.keep.simple.blocks.in.one.line"), WRAPPING_KEEP); + addOption("KEEP_SIMPLE_METHODS_IN_ONE_LINE", ApplicationBundle.message("wrapping.keep.simple.methods.in.one.line"), WRAPPING_KEEP); + addOption("KEEP_SIMPLE_CLASSES_IN_ONE_LINE", ApplicationBundle.message("wrapping.keep.simple.classes.in.one.line"), WRAPPING_KEEP); addOption("CLASS_BRACE_STYLE", ApplicationBundle.message("wrapping.brace.placement.class.declaration"), WRAPPING_BRACES, BRACE_PLACEMENT_OPTIONS, BRACE_PLACEMENT_VALUES); addOption("METHOD_BRACE_STYLE", ApplicationBundle.message("wrapping.brace.placement.method.declaration"), WRAPPING_BRACES, BRACE_PLACEMENT_OPTIONS, BRACE_PLACEMENT_VALUES); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatAndOptimizeImportsProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatAndOptimizeImportsProcessor.java index 8d82a14c80be..f5ed69680a5f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatAndOptimizeImportsProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatAndOptimizeImportsProcessor.java @@ -21,6 +21,8 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -71,7 +73,13 @@ public class ReformatAndOptimizeImportsProcessor extends AbstractLayoutCodeProce return new Runnable() { public void run() { r1.run(); - r2.run(); + CodeStyleManagerImpl.setSequentialProcessingAllowed(false); + try { + r2.run(); + } + finally { + CodeStyleManagerImpl.setSequentialProcessingAllowed(true); + } } }; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 106e016d7b86..c2f09f4c935c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -239,11 +239,10 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { @NotNull private LookupImpl obtainLookup(Editor editor) { LookupImpl existing = (LookupImpl)LookupManager.getActiveLookup(editor); - if (existing != null && existing.isCompletion()) { + if (existing != null && existing.isCompletion() && !existing.isHintMode()) { existing.markReused(); if (!autopopup) { existing.setFocused(true); - existing.setHintMode(false); } return existing; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java index 9336b40c3c3b..ab766b30cb10 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -392,10 +392,10 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement public void closeAndFinish(boolean hideLookup) { final CompletionProgressIndicator current = CompletionServiceImpl.getCompletionService().getCurrentCompletion(); - LOG.assertTrue(this == current, current); + LOG.assertTrue(this == current, current + "!=" + this); Lookup lookup = LookupManager.getActiveLookup(myEditor); - LOG.assertTrue(lookup == myLookup, lookup); + LOG.assertTrue(lookup == myLookup, lookup + "; " + this); myLookup.removeLookupListener(myLookupListener); finishCompletionProcess(); CompletionServiceImpl.assertPhase(CompletionPhase.NoCompletion.getClass()); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionSorterImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionSorterImpl.java index 0d7250068c02..a82f8b9b40ef 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionSorterImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionSorterImpl.java @@ -50,12 +50,23 @@ public class CompletionSorterImpl extends CompletionSorter { }; } - @Override public CompletionSorterImpl weighBefore(@NotNull final String beforeId, final LookupElementWeigher weigher) { - return withClassifier(beforeId, true, weighingFactory(weigher)); + @Override public CompletionSorterImpl weighBefore(@NotNull final String beforeId, LookupElementWeigher... weighers) { + assert weighers.length > 0 : "there should be weighers"; + CompletionSorterImpl result = this; + for (LookupElementWeigher weigher : weighers) { + result = result.withClassifier(beforeId, true, weighingFactory(weigher)); + } + return result; } - @Override public CompletionSorterImpl weighAfter(@NotNull final String afterId, final LookupElementWeigher weigher) { - return withClassifier(afterId, false, weighingFactory(weigher)); + @Override public CompletionSorterImpl weighAfter(@NotNull final String afterId, LookupElementWeigher... weighers) { + assert weighers.length > 0 : "there should be weighers"; + CompletionSorterImpl result = this; + for (int i = weighers.length - 1; i >= 0; i--) { + LookupElementWeigher weigher = weighers[i]; + result = result.withClassifier(afterId, false, weighingFactory(weigher)); + } + return result; } @Override public CompletionSorterImpl weigh(final LookupElementWeigher weigher) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightInfoHolder.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightInfoHolder.java index 84df3efe441f..ca74d4685529 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightInfoHolder.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightInfoHolder.java @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * @author Alexey - */ package com.intellij.codeInsight.daemon.impl.analysis; import com.intellij.codeInsight.daemon.impl.HighlightInfo; @@ -34,6 +30,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +/** + * @author Alexey + */ public class HighlightInfoHolder { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder"); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java index 9e2dd837d3d8..8606406f6a06 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java @@ -43,6 +43,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.OrderEntry; @@ -78,10 +79,8 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.LinkedHashSet; +import java.util.*; import java.util.List; -import java.util.Set; public class DocumentationManager { private static final Logger LOG = Logger.getInstance("#" + DocumentationManager.class.getName()); @@ -802,6 +801,17 @@ public class DocumentationManager { result.add(LanguageDocumentation.INSTANCE.forLanguage(baseLanguage)); } } + else if (element instanceof PsiDirectory) { + final Set langs = new HashSet(); + + for (PsiFile file : ((PsiDirectory)element).getFiles()) { + final Language baseLanguage = file.getViewProvider().getBaseLanguage(); + if (!langs.contains(baseLanguage)) { + langs.add(baseLanguage); + result.add(LanguageDocumentation.INSTANCE.forLanguage(baseLanguage)); + } + } + } return CompositeDocumentationProvider.wrapProviders(result); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java index 653c8421ee7b..833b276060b7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java @@ -28,6 +28,7 @@ import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.hint.EditorFragmentComponent; import com.intellij.concurrency.Job; import com.intellij.concurrency.JobUtil; +import com.intellij.injected.editor.EditorWindow; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.Document; @@ -44,7 +45,7 @@ import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.editor.markup.*; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; @@ -291,7 +292,7 @@ public class BraceHighlightingHandler { } private void highlightBraces(final int lBraceOffset, int rBraceOffset, boolean matched, boolean scopeHighlighting) { - if (!matched && myFileType == StdFileTypes.PLAIN_TEXT) { + if (!matched && myFileType == FileTypes.PLAIN_TEXT) { return; } @@ -304,10 +305,8 @@ public class BraceHighlightingHandler { highlightBrace(rBraceOffset, matched); } - if (lBraceOffset >= 0) { - if (!scopeHighlighting) { - highlightBrace(lBraceOffset, matched); - } + if (lBraceOffset >= 0 && !scopeHighlighting) { + highlightBrace(lBraceOffset, matched); } if (!myEditor.equals(FileEditorManager.getInstance(myProject).getSelectedTextEditor())) { @@ -368,13 +367,20 @@ public class BraceHighlightingHandler { } private void registerHighlighter(RangeHighlighter highlighter) { - List highlighters = myEditor.getUserData(BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY); + List highlighters = getHighlightersList(); + highlighters.add(highlighter); + } + + @NotNull + private List getHighlightersList() { + // braces are highlighted across the whole editor, not in each injected editor separately + Editor editor = myEditor instanceof EditorWindow ? ((EditorWindow)myEditor).getDelegate() : myEditor; + List highlighters = editor.getUserData(BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY); if (highlighters == null) { highlighters = new ArrayList(); - myEditor.putUserData(BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY, highlighters); + editor.putUserData(BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY, highlighters); } - - highlighters.add(highlighter); + return highlighters; } private void showScopeHint(final int lbraceStart, final int lbraceEnd) { @@ -405,12 +411,11 @@ public class BraceHighlightingHandler { } public void clearBraceHighlighters() { - List highlighters = myEditor.getUserData(BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY); - if (highlighters == null) return; - myEditor.putUserData(BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY, null); + List highlighters = getHighlightersList(); for (final RangeHighlighter highlighter : highlighters) { highlighter.dispose(); } + highlighters.clear(); } private void lineMarkFragment(int startLine, int endLine, Color color) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java index de8e1eb23ab0..b00d961853ef 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.lookup.impl; import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; @@ -73,11 +74,6 @@ public abstract class LookupActionHandler extends EditorActionHandler { protected void executeInLookup(final LookupImpl lookup, DataContext context) { if (!lookup.isFocused()) { - if (lookup.isPositionedAboveCaret()) { - myOriginalHandler.execute(lookup.getEditor(), context); - return; - } - lookup.setFocused(true); lookup.getList().setSelectedIndex(0); lookup.refreshUi(); @@ -94,16 +90,14 @@ public abstract class LookupActionHandler extends EditorActionHandler { protected void executeInLookup(final LookupImpl lookup, DataContext context) { if (!lookup.isFocused()) { - if (!lookup.isPositionedAboveCaret()) { + if (!UISettings.getInstance().CYCLE_SCROLLING) { myOriginalHandler.execute(lookup.getEditor(), context); return; } lookup.setFocused(true); - final int index = ApplicationManager.getApplication().isUnitTestMode() ? lookup.getItems().size() - 1 : lookup.getList().getLastVisibleIndex(); - lookup.getList().setSelectedIndex(index); + lookup.getList().setSelectedIndex(0); lookup.refreshUi(); - return; } ListScrollingUtil.moveUp(lookup.getList(), 0); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index ca3956129aee..b3f576c62ef8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -1149,7 +1149,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { editor.getContentComponent() ); - final HintHint hintHint = new HintHint(editor, editorPoint).setHighlighterType(true).setContentActive(true); + final HintHint hintHint = new HintHint(editor, editorPoint); final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl(); if (myAutopopupHint == null) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java index 54c84064dc0a..53a3fe3acd77 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java @@ -22,6 +22,7 @@ import com.intellij.codeInsight.completion.CompletionService; import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.codeInsight.template.impl.ListTemplatesHandler; import com.intellij.codeInsight.template.impl.LiveTemplateCompletionContributor; import com.intellij.codeInsight.template.impl.TemplateImpl; import com.intellij.codeInsight.template.impl.TemplateSettings; @@ -51,6 +52,8 @@ public class ChooseItemReplaceAction extends EditorAction { public boolean isEnabled(Editor editor, DataContext dataContext) { LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); if (lookup != null) { + lookup.refreshUi(); // to bring the list model up to date + CompletionProcess completion = CompletionService.getCompletionService().getCurrentCompletion(); if (completion != null && completion.isAutopopupCompletion() && hasTemplatePrefix(lookup, TemplateSettings.TAB_CHAR)) { return false; @@ -60,7 +63,6 @@ public class ChooseItemReplaceAction extends EditorAction { return true; } - lookup.refreshUi(); // to bring the list model up to date return !lookup.getItems().isEmpty(); } return false; @@ -76,7 +78,7 @@ public class ChooseItemReplaceAction extends EditorAction { final int end = editor.getCaretModel().getOffset(); final int start = lookup.getLookupStart(); - final String prefix = editor.getDocument().getText(TextRange.create(start, end)); + final String prefix = !lookup.getItems().isEmpty() ? editor.getDocument().getText(TextRange.create(start, end)) : ListTemplatesHandler.getPrefix(editor.getDocument(), end); final TemplateImpl template = LiveTemplateCompletionContributor.findApplicableTemplate(file, end, prefix); return template != null && shortcutChar == TemplateSettings.getInstance().getShortcutChar(template); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/Template.java b/platform/lang-impl/src/com/intellij/codeInsight/template/Template.java index 0da41ec1cb35..43dba460aa10 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/Template.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/Template.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.template; import com.intellij.codeInsight.template.impl.Variable; +import com.intellij.openapi.editor.RangeMarker; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateBuilderImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateBuilderImpl.java index 25d5744b9672..4e41928a7ba2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateBuilderImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateBuilderImpl.java @@ -111,6 +111,14 @@ public class TemplateBuilderImpl implements TemplateBuilder { myElements.add(key); } + public void replaceElement(PsiElement element, TextRange textRange, String primaryVariableName, String otherVariableName, boolean alwaysStopAt) { + final RangeMarker key = myDocument.createRangeMarker(textRange.shiftRight(element.getTextRange().getStartOffset())); + myAlwaysStopAtMap.put(key, alwaysStopAt ? Boolean.TRUE : Boolean.FALSE); + myVariableNamesMap.put(key, primaryVariableName); + myVariableExpressions.put(key, otherVariableName); + myElements.add(key); + } + public void replaceElement(PsiElement element, Expression expression) { final RangeMarker key = wrapElement(element); replaceElement(key, expression); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/ListTemplatesHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/ListTemplatesHandler.java index 2d2e49487640..12a3b0760a57 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/ListTemplatesHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/ListTemplatesHandler.java @@ -107,7 +107,7 @@ public class ListTemplatesHandler implements CodeInsightActionHandler { return true; } - private static String getPrefix(Document document, int offset) { + public static String getPrefix(Document document, int offset) { CharSequence chars = document.getCharsSequence(); int start = offset; while (true) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java index a1a9f3bf567c..ce7303c93d7d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java @@ -19,6 +19,7 @@ package com.intellij.codeInsight.template.impl; import com.intellij.codeInsight.template.Expression; import com.intellij.codeInsight.template.Template; import com.intellij.codeInsight.template.TemplateContextType; +import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.options.SchemeElement; import com.intellij.openapi.util.text.StringUtil; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/LineEndWithSelectionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/LineEndWithSelectionHandler.java new file mode 100644 index 000000000000..2c6ae0e7caeb --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/LineEndWithSelectionHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.template.impl.editorActions; + +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; + +/** + * User: anna + * Date: 2/22/11 + */ +public class LineEndWithSelectionHandler extends LineStartEndWithSelectionHandler { + public LineEndWithSelectionHandler(final EditorActionHandler originalHandler) { + super(originalHandler, false); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/LineStartEndWithSelectionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/LineStartEndWithSelectionHandler.java new file mode 100644 index 000000000000..c0b832f9e479 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/LineStartEndWithSelectionHandler.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight.template.impl.editorActions; + +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; +import com.intellij.openapi.util.TextRange; + +public abstract class LineStartEndWithSelectionHandler extends EditorActionHandler { + private final EditorActionHandler myOriginalHandler; + boolean myIsHomeHandler; + + public LineStartEndWithSelectionHandler(final EditorActionHandler originalHandler, boolean isHomeHandler) { + myOriginalHandler = originalHandler; + myIsHomeHandler = isHomeHandler; + } + + public void execute(Editor editor, DataContext dataContext) { + final TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); + if (templateState != null && !templateState.isFinished()) { + final TextRange range = templateState.getCurrentVariableRange(); + final int caretOffset = editor.getCaretModel().getOffset(); + if (range != null && range.getStartOffset() <= caretOffset && caretOffset <= range.getEndOffset()) { + int offsetToMove = myIsHomeHandler ? range.getStartOffset() : range.getEndOffset(); + editor.getCaretModel().moveToOffset(offsetToMove); + editor.getSelectionModel().setSelection(myIsHomeHandler ? offsetToMove : caretOffset, myIsHomeHandler ? caretOffset : offsetToMove); + return; + } + } + myOriginalHandler.execute(editor, dataContext); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/LineStartWithSelectionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/LineStartWithSelectionHandler.java new file mode 100644 index 000000000000..fe390b8fc842 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/LineStartWithSelectionHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.template.impl.editorActions; + +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; + +/** + * User: anna + * Date: 2/22/11 + */ +public class LineStartWithSelectionHandler extends LineStartEndWithSelectionHandler { + public LineStartWithSelectionHandler(final EditorActionHandler originalHandler) { + super(originalHandler, true); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/SelectAllHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/SelectAllHandler.java new file mode 100644 index 000000000000..b19d7da4dbbb --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/SelectAllHandler.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.codeInsight.template.impl.editorActions; + +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; +import com.intellij.openapi.util.TextRange; + +public class SelectAllHandler extends EditorActionHandler { + private final EditorActionHandler myOriginalHandler; + + public SelectAllHandler(final EditorActionHandler originalHandler) { + myOriginalHandler = originalHandler; + } + + public void execute(Editor editor, DataContext dataContext) { + final TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); + if (templateState != null && !templateState.isFinished()) { + final TextRange range = templateState.getCurrentVariableRange(); + final int caretOffset = editor.getCaretModel().getOffset(); + if (range != null && range.getStartOffset() <= caretOffset && caretOffset <= range.getEndOffset()) { + editor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset()); + return; + } + } + myOriginalHandler.execute(editor, dataContext); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/RunInspectionAction.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/RunInspectionAction.java index b5dbefcb4d96..0e074c0538a9 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/RunInspectionAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/RunInspectionAction.java @@ -27,20 +27,16 @@ import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.GotoActionBase; +import com.intellij.ide.util.gotoByName.ChooseByNameFilter; import com.intellij.ide.util.gotoByName.ChooseByNamePopup; -import com.intellij.ide.util.gotoByName.ChooseByNamePopupComponent; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; +import com.intellij.psi.*; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -57,26 +53,30 @@ public class RunInspectionAction extends GotoActionBase { @Override protected void gotoActionPerformed(final AnActionEvent e) { final Project project = e.getData(PlatformDataKeys.PROJECT); + if (project == null) return; + + PsiDocumentManager.getInstance(project).commitAllDocuments(); + final PsiElement psiElement = LangDataKeys.PSI_ELEMENT.getData(e.getDataContext()); final PsiFile psiFile = LangDataKeys.PSI_FILE.getData(e.getDataContext()); final VirtualFile virtualFile = LangDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); - if (project == null || virtualFile == null) return; + if (virtualFile == null) return; + FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.inspection"); - final ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, new GotoInspectionModel(project), getPsiContext(e)); - popup.setSearchInAnyPlace(true); - popup.invoke(new ChooseByNamePopupComponent.Callback() { - public void onClose() { - if (RunInspectionAction.class.equals(myInAction)) { - myInAction = null; - } + final GotoInspectionModel model = new GotoInspectionModel(project); + showNavigationPopup(e, model, new GotoActionCallback() { + @Override + protected ChooseByNameFilter createFilter(ChooseByNamePopup popup) { + popup.setSearchInAnyPlace(true); + return super.createFilter(popup); } - public void elementChosen(Object element) { - final InspectionProfileEntry profileEntry = (InspectionProfileEntry)element; - runInspection(project, profileEntry, virtualFile, psiElement, psiFile); + @Override + public void elementChosen(ChooseByNamePopup popup, Object element) { + runInspection(project, (InspectionProfileEntry)element, virtualFile, psiElement, psiFile); } - }, ModalityState.current(), true); + }); } private static void runInspection(@NotNull Project project, diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/ProblemDescriptorImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/ProblemDescriptorImpl.java index ab434c9165c7..2ae97b01bbbe 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/ProblemDescriptorImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/ProblemDescriptorImpl.java @@ -160,6 +160,13 @@ public class ProblemDescriptorImpl extends CommonProblemDescriptorImpl implement return myEnforcedTextAttributes; } + public TextRange getTextRangeForNavigation() { + TextRange textRange = getTextRange(); + if (textRange == null) return null; + PsiElement element = getPsiElement(); + return InjectedLanguageManager.getInstance(element.getProject()).injectedToHost(element, element.getTextRange()); + } + public TextRange getTextRange() { PsiElement startElement = getStartElement(); PsiElement endElement = myEndSmartPointer == null ? startElement : getEndElement(); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index c0008e364fb1..dafc108e254f 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -645,7 +645,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren if (virtualFile != null) { int startOffset = psiElement.getTextOffset(); if (descriptor instanceof ProblemDescriptorImpl) { - final TextRange textRange = ((ProblemDescriptorImpl)descriptor).getTextRange(); + final TextRange textRange = ((ProblemDescriptorImpl)descriptor).getTextRangeForNavigation(); if (textRange != null) { if (virtualFile instanceof VirtualFileWindow) { virtualFile = ((VirtualFileWindow)virtualFile).getDelegate(); diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index af25959298ce..bc703320ecca 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -21,6 +21,7 @@ import com.intellij.ide.impl.TypeSafeDataProviderAdapter; import com.intellij.lang.Language; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.*; @@ -373,7 +374,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { HighlighterTargetArea.EXACT_RANGE); final String text = consoleEditor.getDocument().getText(textRange); - //offset can be changed after text trimming after insert due to buffer constraints + //offset can be changed after text trimming after insert due to buffer constraints appendToHistoryDocument(history, text); int offset = history.getTextLength() - text.length(); final int localStartOffset = textRange.getStartOffset(); @@ -617,10 +618,17 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { attributes = additionalType.getAttributes().clone(); attributes.setBackgroundColor(mainAttributes.getBackgroundColor()); } - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - console.printToHistory(string, attributes); - } - }, ModalityState.stateForComponent(console.getComponent())); + + Application application = ApplicationManager.getApplication(); + if (application.isDispatchThread()) { + console.printToHistory(string, attributes); + } + else { + application.invokeLater(new Runnable() { + public void run() { + console.printToHistory(string, attributes); + } + }, ModalityState.stateForComponent(console.getComponent())); + } } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index bcbdf98db357..c7527036d028 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -731,6 +731,11 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo return true; } + @TestOnly + public void flushDeferredText() { + flushDeferredText(false); + } + private void flushDeferredText(boolean clear) { ApplicationManager.getApplication().assertIsDispatchThread(); if (myProject.isDisposed()) { diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java index c7a4b291ee56..c44d17fc9471 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java @@ -21,6 +21,7 @@ import com.intellij.execution.configuration.ConfigurationFactoryEx; import com.intellij.execution.configurations.*; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.options.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; @@ -332,12 +333,26 @@ class RunConfigurable extends BaseConfigurable { ? configurationType.getConfigurationTypeDescription() : ExecutionBundle.message("run.configuration.default.type.description"); browser.setText(ExecutionBundle.message("empty.run.configuration.panel.text.label", font.getFontName(), addUrl, defaultsURL, - configurationTypeDescription)); + configurationTypeDescription, configurationType != null ? configurationType.getId() : "")); browser.setPreferredSize(new Dimension(200, 50)); browser.addHyperlinkListener(new HyperlinkListener() { public void hyperlinkUpdate(final HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - if (Comparing.strEqual(e.getDescription(), "add")) { + final String description = e.getDescription(); + final String addPrefix = "add"; + if (description.startsWith(addPrefix)) { + final String typeId = description.substring(addPrefix.length()); + if (!typeId.isEmpty()) { + for (ConfigurationType type : Extensions.getExtensions(ConfigurationType.CONFIGURATION_TYPE_EP)) { + if (Comparing.strEqual(type.getId(), typeId)) { + final ConfigurationFactory[] factories = type.getConfigurationFactories(); + if (factories.length > 0) { + createNewConfiguration(factories[0]); + } + return; + } + } + } new MyToolbarAddAction().actionPerformed(null); } } diff --git a/java/execution/impl/src/com/intellij/execution/impl/RunConfigurationRefactoringElementListenerProvider.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationRefactoringElementListenerProvider.java similarity index 80% rename from java/execution/impl/src/com/intellij/execution/impl/RunConfigurationRefactoringElementListenerProvider.java rename to platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationRefactoringElementListenerProvider.java index 0b3b8f13629a..5940a623731c 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/RunConfigurationRefactoringElementListenerProvider.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurationRefactoringElementListenerProvider.java @@ -18,6 +18,7 @@ package com.intellij.execution.impl; import com.intellij.execution.RunManager; import com.intellij.execution.configurations.RefactoringListenerProvider; import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.PsiElement; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.listeners.RefactoringElementListenerComposite; @@ -27,13 +28,22 @@ import com.intellij.refactoring.listeners.RefactoringElementListenerProvider; * @author spleaner */ public class RunConfigurationRefactoringElementListenerProvider implements RefactoringElementListenerProvider { + private static final Logger LOG = Logger.getInstance("#com.intellij.execution.impl.RunConfigurationRefactoringElementListenerProvider"); + public RefactoringElementListener getListener(final PsiElement element) { RefactoringElementListenerComposite composite = null; final RunConfiguration[] configurations = RunManager.getInstance(element.getProject()).getAllConfigurations(); for (RunConfiguration configuration : configurations) { if (configuration instanceof RefactoringListenerProvider) { // todo: perhaps better way to handle listeners? - final RefactoringElementListener listener = ((RefactoringListenerProvider)configuration).getRefactoringElementListener(element); + final RefactoringElementListener listener; + try { + listener = ((RefactoringListenerProvider)configuration).getRefactoringElementListener(element); + } + catch (Exception e) { + LOG.error(e); + continue; + } if (listener != null) { if (composite == null) { composite = new RefactoringElementListenerComposite(); diff --git a/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java b/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java index ef936fc4706b..f1f6b203f471 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java +++ b/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java @@ -30,18 +30,14 @@ import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.actions.CloseAction; import com.intellij.ide.CommonActionsManager; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.actions.ScrollToTheEndToolbarAction; -import com.intellij.openapi.editor.actions.ToggleUseSoftWrapsToolbarAction; import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; -import com.intellij.openapi.editor.ex.util.EditorUtil; -import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; @@ -60,8 +56,8 @@ import java.util.List; /** * @author oleg - * This class provides basic functionality for running consoles. - * It launches external process and handles line input with history + * This class provides basic functionality for running consoles. + * It launches external process and handles line input with history */ public abstract class AbstractConsoleRunnerWithHistory { private final Project myProject; @@ -96,6 +92,23 @@ public abstract class AbstractConsoleRunnerWithHistory { // Create Server process final Process process = createProcess(myProvider); + Application application = ApplicationManager.getApplication(); + + if (application.isDispatchThread()) { + initConsoleUI(process); + } + else { + application.invokeLater(new Runnable() { + @Override + public void run() { + initConsoleUI(process); + } + }); + } + } + + + private void initConsoleUI(Process process) { // Init console view myConsoleView = createConsoleView(); @@ -257,7 +270,7 @@ public abstract class AbstractConsoleRunnerWithHistory { // Check if we have active lookup or if we can move in editor return LookupManager.getActiveLookup(consoleEditor) != null || document.getLineNumber(caretModel.getOffset()) < document.getLineCount() - 1 && - !StringUtil.isEmptyOrSpaces(document.getText().substring(caretModel.getOffset())); + !StringUtil.isEmptyOrSpaces(document.getText().substring(caretModel.getOffset())); } }; } diff --git a/platform/lang-impl/src/com/intellij/execution/runners/ConsoleExecuteActionHandler.java b/platform/lang-impl/src/com/intellij/execution/runners/ConsoleExecuteActionHandler.java index 6f4571eb3502..3f6f84a9c98d 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/ConsoleExecuteActionHandler.java +++ b/platform/lang-impl/src/com/intellij/execution/runners/ConsoleExecuteActionHandler.java @@ -31,6 +31,7 @@ import java.io.OutputStream; public class ConsoleExecuteActionHandler { private final ProcessHandler myProcessHandler; private final boolean myPreserveMarkup; + private boolean myAddCurrentToHistory; public ConsoleExecuteActionHandler(ProcessHandler processHandler, boolean preserveMarkup) { myProcessHandler = processHandler; @@ -47,7 +48,9 @@ public class ConsoleExecuteActionHandler { final TextRange range = new TextRange(0, document.getTextLength()); languageConsole.getCurrentEditor().getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset()); - languageConsole.addCurrentToHistory(range, false, myPreserveMarkup); + if (myAddCurrentToHistory) { + languageConsole.addCurrentToHistory(range, false, myPreserveMarkup); + } languageConsole.setInputText(""); if (!StringUtil.isEmptyOrSpaces(text)) { consoleHistoryModel.addToHistory(text); @@ -57,10 +60,10 @@ public class ConsoleExecuteActionHandler { } public void processLine(String line) { - sendLine(line + "\n"); + sendText(line + "\n"); } - public void sendLine(String line) { + public void sendText(String line) { //final Charset charset = myProcessHandler.getCharset(); final OutputStream outputStream = myProcessHandler.getProcessInput(); try { @@ -73,4 +76,8 @@ public class ConsoleExecuteActionHandler { // ignore } } + + public void setAddCurrentToHistory(boolean addCurrentToHistory) { + myAddCurrentToHistory = addCurrentToHistory; + } } diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java index bfd283667e94..301dd51768a9 100644 --- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java +++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java @@ -30,14 +30,13 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.editor.event.SelectionEvent; import com.intellij.openapi.editor.event.SelectionListener; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.ui.popup.PopupChooserBuilder; +import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.TextRange; @@ -49,6 +48,7 @@ import com.intellij.psi.impl.cache.impl.id.IdTableBuilding; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.LightColors; import com.intellij.ui.NonFocusableCheckBox; +import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBList; import com.intellij.ui.components.labels.LinkLabel; import com.intellij.ui.components.labels.LinkListener; @@ -79,6 +79,10 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec private JTextField myReplaceField; private final Color myDefaultBackground; + private JButton myReplaceButton; + private JButton myReplaceAllButton; + private JButton myExcludeButton; + private JCheckBox myPreserveCase; private JCheckBox mySelectionOnly; @@ -95,7 +99,10 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec private final JCheckBox myCbInComments; private final JCheckBox myCbInLiterals; - private final LivePreviewControllerBase myLivePreviewController; + private final JPanel myOptionsPane; + private final LinkLabel myMoreOptionsButton; + + private final MyLivePreviewController myLivePreviewController; private final LivePreview myLivePreview; @@ -103,6 +110,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec private boolean myListeningSelection = false; private boolean myToChangeSelection = true; private SearchResults mySearchResults; + private Balloon myOptionsBalloon; @Nullable public Object getData(@NonNls final String dataId) { @@ -149,25 +157,26 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec } updateSelection(); + updateExcludeStatus(); } @Override public void cursorMoved() { updateSelection(); + updateExcludeStatus(); } private void updateSelection() { + SelectionModel selection = myEditor.getSelectionModel(); if (myToChangeSelection && (mySelectionOnly == null || !mySelectionOnly.isSelected())) { LiveOccurrence cursor = mySearchResults.getCursor(); if (cursor != null) { TextRange range = cursor.getPrimaryRange(); - myEditor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset()); + selection.setSelection(range.getStartOffset(), range.getEndOffset()); myEditor.getCaretModel().moveToOffset(range.getEndOffset()); myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - myEditor.getCaretModel().moveToOffset(range.getStartOffset()); - myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } myToChangeSelection = false; } @@ -191,23 +200,15 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec mySearchResults = new SearchResults(myEditor); myLivePreview = new LivePreview(mySearchResults); - myLivePreviewController = new LivePreviewControllerBase(mySearchResults, myLivePreview) { - @Override - public void getFocusBack() { - mySearchField.requestFocus(); - } - }; + myLivePreviewController = new MyLivePreviewController(); + mySearchResults.addListener(this); setMatchesLimit(MATCHES_LIMIT); - JPanel leadPanel = createLeadPane(); + final JPanel leadPanel = createLeadPane(); add(leadPanel, BorderLayout.WEST); - if (myIsReplace) { - configureReplacementPane(); - myReplaceField.putClientProperty("AuxEditorComponent", Boolean.TRUE); - } mySearchField = createTextField(); leadPanel.add(mySearchField); @@ -231,17 +232,36 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec final JCheckBox cbMatchCase = new NonFocusableCheckBox("Case sensitive"); myCbWholeWords = new NonFocusableCheckBox("Match whole words only"); myCbRegexp = new NonFocusableCheckBox("Regex"); - myCbInComments = new NonFocusableCheckBox("In comments"); - myCbInLiterals = new NonFocusableCheckBox("In literals"); + myCbInComments = new NonFocusableCheckBox("Search in comments only"); + myCbInLiterals = new NonFocusableCheckBox("Search in literals only"); + + myOptionsPane = new JPanel(); + myOptionsPane.setLayout(new BoxLayout(myOptionsPane, BoxLayout.Y_AXIS)); leadPanel.add(cbMatchCase); - leadPanel.add(myCbWholeWords); + myOptionsPane.add(myCbWholeWords); leadPanel.add(myCbRegexp); if (FindManagerImpl.ourHasSearchInCommentsAndLiterals) { - leadPanel.add(myCbInComments); - leadPanel.add(myCbInLiterals); + myOptionsPane.add(myCbInComments); + myOptionsPane.add(myCbInLiterals); } + myMoreOptionsButton = new LinkLabel("more options", null, new LinkListener() { + @Override + public void linkSelected(LinkLabel aSource, Object aLinkData) { + if (myOptionsBalloon == null || myOptionsBalloon.isDisposed()) { + BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createBalloonBuilder(myOptionsPane); + balloonBuilder.setFillColor(myOptionsPane.getBackground()); + Point point = new Point((int)(myMoreOptionsButton.getX() + myMoreOptionsButton.getBounds().getWidth()/2), + (int)(myMoreOptionsButton.getY() + myMoreOptionsButton.getBounds().getHeight()/2)); + myOptionsBalloon = balloonBuilder.createBalloon(); + myOptionsBalloon.show(new RelativePoint(leadPanel, point), Balloon.Position.below); + } + } + }); + + leadPanel.add(myMoreOptionsButton); + cbMatchCase.setSelected(isCaseSensitive()); myCbWholeWords.setSelected(isWholeWords()); myCbRegexp.setSelected(isRegexp()); @@ -250,7 +270,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec cbMatchCase.setMnemonic('C'); myCbWholeWords.setMnemonic('M'); - myCbRegexp.setMnemonic('R'); + myCbRegexp.setMnemonic('x'); myCbInComments.setMnemonic('o'); myCbInLiterals.setMnemonic('l'); @@ -260,6 +280,12 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec setSmallerFontAndOpaque(myCbInComments); setSmallerFontAndOpaque(myCbInLiterals); + if (myIsReplace) { + configureReplacementPane(); + myReplaceField.putClientProperty("AuxEditorComponent", Boolean.TRUE); + } + + cbMatchCase.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { final boolean b = cbMatchCase.isSelected(); @@ -376,6 +402,12 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec JPanel replacement = createLeadPane(); myReplaceField = createTextField(); configureTextField(myReplaceField); + myReplaceField.registerKeyboardAction(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + myLivePreviewController.performReplace(); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED); replacement.add(myReplaceField); add(replacement, BorderLayout.SOUTH); myPreserveCase = new JCheckBox("Preserve case"); @@ -405,13 +437,65 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec myPreserveCase.setSelected(findInFileModel.isPreserveCase()); myPreserveCase.setEnabled(!findInFileModel.isRegularExpressions()); - replacement.add(mySelectionOnly); - replacement.add(myPreserveCase); + myReplaceButton = new JButton("Replace"); + myReplaceButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + myLivePreviewController.performReplace(); + } + }); + myReplaceButton.setMnemonic('p'); + + myReplaceAllButton = new JButton("Replace all"); + myReplaceAllButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + myLivePreviewController.performReplaceAll(); + } + }); + myReplaceAllButton.setMnemonic('a'); + + myExcludeButton = new JButton(""); + updateExcludeStatus(); + myExcludeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + myLivePreviewController.exclude(); + } + }); + myExcludeButton.setMnemonic('l'); + + replacement.add(myReplaceButton); + replacement.add(myReplaceAllButton); + replacement.add(myExcludeButton); + + myOptionsPane.add(mySelectionOnly); + myOptionsPane.add(myPreserveCase); + + setSmallerFontAndOpaque(myReplaceButton); + setSmallerFontAndOpaque(myReplaceAllButton); + setSmallerFontAndOpaque(myExcludeButton); + setSmallerFontAndOpaque(mySelectionOnly); setSmallerFontAndOpaque(myPreserveCase); setSmallerFont(myReplaceField); } + private void updateExcludeStatus() { + if (myExcludeButton != null) { + LiveOccurrence cursor = mySearchResults.getCursor(); + myExcludeButton.setText(cursor == null || !mySearchResults.isExcluded(cursor) ? "exclude" : "include"); + myReplaceAllButton.setEnabled(mySearchResults.hasMatches()); + if (cursor != null) { + myExcludeButton.setEnabled(true); + myReplaceButton.setEnabled(true); + } else { + myExcludeButton.setEnabled(false); + myReplaceButton.setEnabled(false); + } + } + } + private void updateModelWithSelectionMode(FindModel findInFileModel) { final boolean b = mySelectionOnly.isSelected(); findInFileModel.setGlobal(!b); @@ -528,6 +612,13 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec } } + public void replaceCurrent() { + if (mySearchResults.getCursor() != null) { + String replacement = myLivePreviewController.getStringToReplace(myEditor, mySearchResults.getCursor()); + myLivePreviewController.performReplace(mySearchResults.getCursor(), replacement, myEditor); + } + } + private static void setSmallerFontAndOpaque(final JComponent component) { setSmallerFont(component); component.setOpaque(false); @@ -550,6 +641,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec myEditor.getSelectionModel().removeSelection(); } IdeFocusManager.getInstance(myProject).requestFocus(myEditor.getContentComponent(), false); + mySearchResults.dispose(); myLivePreview.cleanUp(); myEditor.setHeaderComponent(null); addCurrentTextToRecents(); @@ -635,7 +727,9 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec model.setGlobal(!mySelectionOnly.isSelected()); model.setPreserveCase(myPreserveCase.isEnabled() && myPreserveCase.isSelected()); } - myToChangeSelection = allowedToChangedEditorSelection; + if (!myToChangeSelection) { + myToChangeSelection = allowedToChangedEditorSelection; + } myLivePreviewController.updateInBackground(model); } @@ -901,4 +995,36 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec g2d.setPaint(null); g.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1); } + + private class MyLivePreviewController extends LivePreviewControllerBase { + public MyLivePreviewController() { + super(EditorSearchComponent.this.mySearchResults, EditorSearchComponent.this.myLivePreview); + } + + @Override + public void getFocusBack() { + mySearchField.requestFocus(); + } + + @Override + public TextRange performReplace(LiveOccurrence occurrence, String replacement, Editor editor) { + myToChangeSelection = true; + return super + .performReplace(occurrence, replacement, editor); //To change body of overridden methods use File | Settings | File Templates. + } + + public void performReplace() { + String replacement = getStringToReplace(myEditor, mySearchResults.getCursor()); + performReplace(mySearchResults.getCursor(), replacement, myEditor); + getFocusBack(); + } + + public void exclude() { + mySearchResults.exclude(mySearchResults.getCursor()); + } + + public void performReplaceAll() { + performReplaceAll(myEditor); + } + } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java index 8deac659bc64..d87b1a5e8980 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java @@ -30,6 +30,7 @@ import com.intellij.openapi.editor.markup.CustomHighlighterRenderer; import com.intellij.openapi.editor.markup.EffectType; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.BalloonBuilder; import com.intellij.openapi.ui.popup.JBPopupFactory; @@ -50,7 +51,7 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele public interface Delegate { @Nullable - String getReplacementPreviewText(Editor editor, LiveOccurrence liveOccurrence); + String getStringToReplace(Editor editor, LiveOccurrence liveOccurrence); @Nullable TextRange performReplace(LiveOccurrence occurrence, String replacement, Editor editor); @@ -187,12 +188,15 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele editor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener); } myVisibleAreaListenersToRemove.clear(); - for (RangeHighlighter h : myHighlighters) { - HighlightManager.getInstance(mySearchResults.getProject()).removeSegmentHighlighter(editor, h); - } - if (myCursorHighlighter != null) { - HighlightManager.getInstance(mySearchResults.getProject()).removeSegmentHighlighter(editor, myCursorHighlighter); - myCursorHighlighter = null; + Project project = mySearchResults.getProject(); + if (!project.isDisposed()) { + for (RangeHighlighter h : myHighlighters) { + HighlightManager.getInstance(project).removeSegmentHighlighter(editor, h); + } + if (myCursorHighlighter != null) { + HighlightManager.getInstance(project).removeSegmentHighlighter(editor, myCursorHighlighter); + myCursorHighlighter = null; + } } } } @@ -216,7 +220,7 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele final LiveOccurrence cursor = mySearchResults.getCursor(); final Editor editor = mySearchResults.getEditor(); if (myDelegate != null && cursor != null) { - String replacementPreviewText = myDelegate.getReplacementPreviewText(editor, cursor); + String replacementPreviewText = myDelegate.getStringToReplace(editor, cursor); if (replacementPreviewText != null) { ReplacementView replacementView = new ReplacementView(replacementPreviewText, cursor); @@ -247,11 +251,14 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele } private void highlightRange(TextRange textRange, TextAttributes attributes, Collection highlighters) { - HighlightManager highlightManager = HighlightManager.getInstance(mySearchResults.getProject()); - if (highlightManager != null) { - highlightManager.addRangeHighlight(mySearchResults.getEditor(), - textRange.getStartOffset(), textRange.getEndOffset(), - attributes, false, highlighters); + Project project = mySearchResults.getProject(); + if (!project.isDisposed()) { + HighlightManager highlightManager = HighlightManager.getInstance(project); + if (highlightManager != null) { + highlightManager.addRangeHighlight(mySearchResults.getEditor(), + textRange.getStartOffset(), textRange.getEndOffset(), + attributes, false, highlighters); + } } } @@ -269,7 +276,6 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele drawSegment(editor, new TextRange(offset, newOffset), g); offset = newOffset+1; } - } private static void drawSegment(Editor editor, Segment highlighter, Graphics g) { diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java index a94ec03b51a1..8e053661000f 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java @@ -26,6 +26,21 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil private SearchResults mySearchResults; private LivePreview myLivePreview; + public interface ReplaceListener { + void replacePerformed(LiveOccurrence occurrence, final String replacement, final Editor editor); + void replaceAllPerformed(Editor e); + } + + private ReplaceListener myReplaceListener; + + public ReplaceListener getReplaceListener() { + return myReplaceListener; + } + + public void setReplaceListener(ReplaceListener replaceListener) { + myReplaceListener = replaceListener; + } + public LivePreviewControllerBase(SearchResults searchResults, LivePreview livePreview) { mySearchResults = searchResults; myLivePreview = livePreview; @@ -57,7 +72,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil } @Override - public String getReplacementPreviewText(Editor editor, LiveOccurrence liveOccurrence) { + public String getStringToReplace(Editor editor, LiveOccurrence liveOccurrence) { String foundString = editor.getDocument().getText(liveOccurrence.getPrimaryRange()); String documentText = editor.getDocument().getText(); FindModel currentModel = mySearchResults.getFindModel(); @@ -86,21 +101,27 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil public TextRange performReplace(final LiveOccurrence occurrence, final String replacement, final Editor editor) { TextRange range = occurrence.getPrimaryRange(); FindModel findModel = mySearchResults.getFindModel(); + TextRange result = null; try { - return FindUtil.doReplace(editor.getProject(), editor.getDocument(), findModel, new FindResultImpl(range.getStartOffset(), range.getEndOffset()), + result = FindUtil.doReplace(editor.getProject(), editor.getDocument(), findModel, new FindResultImpl(range.getStartOffset(), range.getEndOffset()), FindManager.getInstance(editor.getProject()).getStringToReplace(editor.getDocument().getText(range), findModel), true, new ArrayList>()); } catch (FindManager.MalformedReplacementStringException e) { /**/ } + if (myReplaceListener != null) { + myReplaceListener.replacePerformed(occurrence, replacement, editor); + } mySearchResults.updateThreadSafe(findModel); - return null; + return result; } @Override public void performReplaceAll(Editor e) { - FindUtil.replace(e.getProject(), e, 0, mySearchResults.getFindModel(), this); + FindUtil.replace(e.getProject(), e, + mySearchResults.getFindModel().isGlobal() ? 0 : mySearchResults.getEditor().getSelectionModel().getSelectionStart(), + mySearchResults.getFindModel(), this); } @Override diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/ReplacementView.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/ReplacementView.java index ea66fc678db6..927879bf7e7f 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/ReplacementView.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/ReplacementView.java @@ -1,12 +1,7 @@ package com.intellij.find.impl.livePreview; -import com.intellij.ide.IdeTooltipManager; -import com.intellij.openapi.util.SystemInfo; - import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; public class ReplacementView extends JPanel { @@ -29,7 +24,6 @@ public class ReplacementView extends JPanel { public void setDelegate(Delegate delegate) { this.myDelegate = delegate; - updateStatusLabel(); } @Override @@ -39,87 +33,8 @@ public class ReplacementView extends JPanel { public ReplacementView(final String replacement, final LiveOccurrence occurrence) { myReplacement = replacement; - myOccurrence = occurrence; - setLayout(new GridBagLayout()); - - GridBagConstraints c = new GridBagConstraints(); - - JLabel jLabel = new JLabel(replacement); + JLabel jLabel = new JLabel(myReplacement); jLabel.setForeground(Color.WHITE); - JPanel labelPane = new JPanel(new FlowLayout()) { - @Override - protected void paintComponent(Graphics graphics) {} - }; - labelPane.setAlignmentX(Component.LEFT_ALIGNMENT); - labelPane.add(jLabel); - - c.fill = GridBagConstraints.HORIZONTAL; - c.gridx = c.gridy = 0; - c.gridwidth = 2; - c.gridheight = 1; - add(labelPane, c); - JButton replace = new JButton("Replace"); - - replace.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - if (myDelegate != null) { - myDelegate.performReplacement(occurrence, replacement); - } - } - }); - replace.setPreferredSize(new Dimension(80, 20)); - replace.setMnemonic('R'); - JPanel buttonsPane = new JPanel(){ - @Override - protected void paintComponent(Graphics graphics) { } - }; - JButton replaceAllButton = new JButton("Replace all"); - - replaceAllButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - if (myDelegate != null) { - myDelegate.performReplaceAll(); - } - } - }); - replaceAllButton.setPreferredSize(new Dimension(100, 20)); - replaceAllButton.setMnemonic('a'); - - myStatusButton = new JButton("Exclude"); - myStatusButton.setPreferredSize(new Dimension(80, 20)); - myStatusButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - myDelegate.exclude(myOccurrence); - updateStatusLabel(); - } - }); - myStatusButton.setMnemonic('l'); - buttonsPane.add(myStatusButton); - - setBackground(IdeTooltipManager.GRAPHITE_COLOR); - if (SystemInfo.isMac) { - Font f = getFont(); - setFont(f.deriveFont(f.getStyle(), f.getSize() - 4)); - } - - buttonsPane.add(replace); - buttonsPane.add(replaceAllButton); - - c.gridx = 0; - c.gridy = 1; - - c.gridwidth = 3; - c.gridheight = 1; - add(buttonsPane, c); - setAlignmentX(Component.LEFT_ALIGNMENT); + add(jLabel); } - - private void updateStatusLabel() { - myStatusButton.setText(myDelegate.isExcluded(myOccurrence) ? "Include" : "Exclude"); - myStatusButton.repaint(); - } - } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java index d6925ef5d915..4dd7da36d644 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java @@ -8,6 +8,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.Nullable; @@ -32,6 +33,8 @@ public class SearchResults { private FindModel myFindModel; private int myMatchesLimit = 100; + private boolean myNotFound = false; + private boolean myDisposed = false; public SearchResults(Editor editor) { myEditor = editor; @@ -131,10 +134,16 @@ public class SearchResults { final ArrayList results = new ArrayList(); if (findModel != null) { - + final Ref selectionRef = new Ref(); + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + selectionRef.set(new TextRange(editor.getSelectionModel().getSelectionStart(), + editor.getSelectionModel().getSelectionEnd())); + } + }); TextRange r = findModel.isGlobal() ? new TextRange(0, Integer.MAX_VALUE) : - new TextRange(editor.getSelectionModel().getSelectionStart(), - editor.getSelectionModel().getSelectionEnd()); + selectionRef.get(); if (r.getLength() == 0) { r = new TextRange(0, Integer.MAX_VALUE); } @@ -172,8 +181,12 @@ public class SearchResults { } } + public void dispose() { + myDisposed = true; + } + private void searchCompleted(List occurrences, int size, Editor editor, FindModel findModel) { - if (editor == getEditor()) { + if (editor == getEditor() && !myDisposed) { myOccurrences = occurrences; final TextRange oldCursorRange = myCursor != null ? myCursor.getPrimaryRange() : null; Collections.sort(myOccurrences, new Comparator() { @@ -195,12 +208,16 @@ public class SearchResults { private void updateCursor(TextRange oldCursorRange) { if (!tryToRepairOldCursor(oldCursorRange)) { - LiveOccurrence afterCaret = firstOccurrenceAfterCaret(); - if (afterCaret != null) { - myCursor = afterCaret; + if (myFindModel != null && oldCursorRange != null && !myFindModel.isGlobal()) { + myCursor = firstOccurrenceAfterOffset(oldCursorRange.getEndOffset()); } else { - LiveOccurrence occurrence = firstVisibleOccurrence(); - myCursor = occurrence; + LiveOccurrence afterCaret = firstOccurrenceAfterCaret(); + if (afterCaret != null) { + myCursor = afterCaret; + } else { + LiveOccurrence occurrence = firstVisibleOccurrence(); + myCursor = occurrence; + } } } } @@ -237,12 +254,31 @@ public class SearchResults { return firstVisibleOccurrence != null ? firstVisibleOccurrence : firstOccurrence; } + @Nullable + private LiveOccurrence firstOccurrenceBeforeCaret() { + int offset = getEditor().getCaretModel().getOffset(); + return firstOccurrenceBeforeOffset(offset); + } + + private LiveOccurrence firstOccurrenceBeforeOffset(int offset) { + for (int i = getOccurrences().size()-1; i >= 0; --i) { + if (getOccurrences().get(i).getPrimaryRange().getEndOffset() < offset) { + return getOccurrences().get(i); + } + } + return null; + } + @Nullable private LiveOccurrence firstOccurrenceAfterCaret() { - LiveOccurrence afterCaret = null; int caret = myEditor.getCaretModel().getOffset(); + return firstOccurrenceAfterOffset(caret); + } + + private LiveOccurrence firstOccurrenceAfterOffset(int offset) { + LiveOccurrence afterCaret = null; for (LiveOccurrence occurrence : getOccurrences()) { - if (occurrence.getPrimaryRange().getStartOffset() >= caret) { + if (occurrence.getPrimaryRange().getStartOffset() >= offset) { if (afterCaret == null || occurrence.getPrimaryRange().getStartOffset() < afterCaret.getPrimaryRange().getStartOffset() ) { afterCaret = occurrence; } @@ -270,7 +306,7 @@ public class SearchResults { @Nullable private LiveOccurrence prevOccurrence(LiveOccurrence o) { for (int i = 0; i < getOccurrences().size(); ++i) { - if (o == getOccurrences().get(i)) { + if (getOccurrences().get(i).equals(o)) { if (i > 0) { return getOccurrences().get(i - 1); } @@ -286,7 +322,7 @@ public class SearchResults { if (found) { return occurrence; } - if (o == occurrence) { + if (occurrence.equals(o)) { found = true; } } @@ -294,18 +330,30 @@ public class SearchResults { } public void prevOccurrence() { - LiveOccurrence prev = prevOccurrence(myCursor); - if (prev == null && !getOccurrences().isEmpty()) { - prev = getOccurrences().get(getOccurrences().size() - 1); + LiveOccurrence next = null; + if (!myFindModel.isGlobal()) { + next = prevOccurrence(myCursor); + } else { + next = firstOccurrenceBeforeCaret(); } - moveCursorTo(prev); + if (next == null && !getOccurrences().isEmpty()) { + next = getOccurrences().get(getOccurrences().size()-1); + } + + moveCursorTo(next); } public void nextOccurrence() { - LiveOccurrence next = nextOccurrence(myCursor); + LiveOccurrence next = null; + if (!myFindModel.isGlobal()) { + next = nextOccurrence(myCursor); + } else { + next = firstOccurrenceAfterCaret(); + } if (next == null && !getOccurrences().isEmpty()) { next = getOccurrences().get(0); } + moveCursorTo(next); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateAction.java b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateAction.java index a1469634bc87..e450ed8f792a 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateAction.java @@ -27,7 +27,7 @@ import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.util.IncorrectOperationException; -import org.apache.velocity.runtime.parser.TemplateParseException; +import org.apache.velocity.runtime.parser.ParseException; import javax.swing.*; @@ -58,7 +58,7 @@ public abstract class CreateFileFromTemplateAction extends CreateFromTemplateAct return psiFile; } } - catch (TemplateParseException e) { + catch (ParseException e) { Messages.showErrorDialog(dir.getProject(), "Error parsing Velocity template: " + e.getMessage(), "Create File from Template"); return null; } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java index 94df0b906239..aea4d046417c 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java @@ -19,7 +19,6 @@ package com.intellij.ide.actions; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.DataManager; import com.intellij.ide.util.gotoByName.ChooseByNamePopup; -import com.intellij.ide.util.gotoByName.ChooseByNamePopupComponent; import com.intellij.ide.util.gotoByName.GotoActionModel; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; @@ -38,15 +37,9 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.action"); - final ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, new GotoActionModel(project, component), getPsiContext(e)); - popup.invoke(new ChooseByNamePopupComponent.Callback() { - public void onClose() { - if (GotoActionAction.class.equals(myInAction)) { - myInAction = null; - } - } - - public void elementChosen(Object element) { + showNavigationPopup(e, new GotoActionModel(project, component), new GotoActionCallback() { + @Override + public void elementChosen(ChooseByNamePopup popup, Object element) { final AnAction action = (AnAction)((Map.Entry)element).getKey(); if (action != null) { ApplicationManager.getApplication().invokeLater(new Runnable() { @@ -62,7 +55,7 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { }, ModalityState.NON_MODAL); } } - }, ModalityState.current(), true); + }); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java index 4c69b3a20065..d55ddc3209ce 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java @@ -16,7 +16,12 @@ package com.intellij.ide.actions; +import com.intellij.ide.util.gotoByName.ChooseByNameFilter; +import com.intellij.ide.util.gotoByName.ChooseByNameModel; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.ChooseByNamePopupComponent; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -25,6 +30,10 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; /** * Author: msk @@ -33,17 +42,8 @@ public abstract class GotoActionBase extends AnAction { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.actions.GotoActionBase"); protected static Class myInAction = null; + private static Map ourLastStrings = new HashMap(); - public static String getInitialText(Editor editor) { - if (editor == null) { - return ""; - } - final String selectedText = editor.getSelectionModel().getSelectedText(); - if (selectedText != null && selectedText.indexOf("\n") < 0) { - return selectedText; - } - return ""; - } public final void actionPerformed(AnActionEvent e) { LOG.assertTrue (!getClass ().equals (myInAction)); @@ -71,6 +71,7 @@ public abstract class GotoActionBase extends AnAction { return true; } + @Nullable public static PsiElement getPsiContext(final AnActionEvent e) { PsiFile file = e.getData(LangDataKeys.PSI_FILE); if (file != null) return file; @@ -78,6 +79,7 @@ public abstract class GotoActionBase extends AnAction { return getPsiContext(project); } + @Nullable public static PsiElement getPsiContext(final Project project) { if (project == null) return null; Editor selectedEditor = FileEditorManager.getInstance(project).getSelectedTextEditor(); @@ -85,4 +87,58 @@ public abstract class GotoActionBase extends AnAction { Document document = selectedEditor.getDocument(); return PsiDocumentManager.getInstance(project).getPsiFile(document); } + + protected static abstract class GotoActionCallback { + @Nullable + protected ChooseByNameFilter createFilter(ChooseByNamePopup popup) { + return null; + } + + public abstract void elementChosen(ChooseByNamePopup popup, Object element); + } + + private static String getInitialText(Editor editor) { + if (editor != null) { + final String selectedText = editor.getSelectionModel().getSelectedText(); + if (selectedText != null && selectedText.indexOf("\n") < 0) { + return selectedText; + } + } + + if (myInAction != null) { + final String lastString = ourLastStrings.get(myInAction); + if (lastString != null) { + return lastString; + } + } + + return ""; + } + + protected static void showNavigationPopup(AnActionEvent e, ChooseByNameModel model, final GotoActionCallback callback) { + final Project project = e.getData(PlatformDataKeys.PROJECT); + + final Class startedAction = myInAction; + final ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, model, getPsiContext(e), getInitialText(e.getData(PlatformDataKeys.EDITOR))); + final ChooseByNameFilter filter = callback.createFilter(popup); + popup.invoke(new ChooseByNamePopupComponent.Callback() { + + @Override + public void onClose() { + ourLastStrings.put(myInAction, popup.getEnteredText()); + if (startedAction.equals(myInAction)) { + myInAction = null; + } + if (filter != null) { + filter.close(); + } + } + + @Override + public void elementChosen(Object element) { + callback.elementChosen(popup, element); + } + }, ModalityState.current(), true); + + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java index 7dd49cbbf3c5..0e2923d92742 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java @@ -19,12 +19,12 @@ package com.intellij.ide.actions; import com.intellij.codeInsight.navigation.NavigationUtil; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.util.gotoByName.*; +import com.intellij.lang.Language; import com.intellij.navigation.ChooseByNameRegistry; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; @@ -43,23 +43,18 @@ public class GotoClassAction extends GotoActionBase implements DumbAware { return; } - FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.class"); PsiDocumentManager.getInstance(project).commitAllDocuments(); + FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.class"); final GotoClassModel2 model = new GotoClassModel2(project); - final ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, model, getPsiContext(e), - getInitialText(e.getData(PlatformDataKeys.EDITOR))); - final ChooseByNameFilter filterUI = new ChooseByNameLanguageFilter(popup, model, GotoClassSymbolConfiguration.getInstance(project), project); - - popup.invoke(new ChooseByNamePopupComponent.Callback() { - public void onClose() { - if (GotoClassAction.class.equals(myInAction)) { - myInAction = null; - } - filterUI.close(); + showNavigationPopup(e, model, new GotoActionCallback() { + @Override + protected ChooseByNameFilter createFilter(ChooseByNamePopup popup) { + return new ChooseByNameLanguageFilter(popup, model, GotoClassSymbolConfiguration.getInstance(project), project); } - public void elementChosen(Object element) { + @Override + public void elementChosen(ChooseByNamePopup popup, Object element) { if (element instanceof PsiElement) { NavigationUtil.activateFileWithPsiElement((PsiElement)element); } @@ -67,7 +62,7 @@ public class GotoClassAction extends GotoActionBase implements DumbAware { ((NavigationItem)element).navigate(true); } } - }, ModalityState.current(), true); + }); } protected boolean hasContributors(DataContext dataContext) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java index 823b1e8a7b72..4e79629b59b8 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java @@ -17,7 +17,10 @@ package com.intellij.ide.actions; import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.ide.util.gotoByName.*; +import com.intellij.ide.util.gotoByName.ChooseByNameFilter; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoFileConfiguration; +import com.intellij.ide.util.gotoByName.GotoFileModel; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; @@ -52,18 +55,14 @@ public class GotoFileAction extends GotoActionBase implements DumbAware { FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.file"); final Project project = e.getData(PlatformDataKeys.PROJECT); final GotoFileModel gotoFileModel = new GotoFileModel(project); - final ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, gotoFileModel, getPsiContext(e), - getInitialText(e.getData(PlatformDataKeys.EDITOR))); - final ChooseByNameFilter filterUI = new GotoFileFilter(popup, gotoFileModel, project); - popup.invoke(new ChooseByNamePopupComponent.Callback() { - public void onClose() { - if (GotoFileAction.class.equals(myInAction)) { - myInAction = null; - } - filterUI.close(); + showNavigationPopup(e, gotoFileModel, new GotoActionCallback() { + @Override + protected ChooseByNameFilter createFilter(ChooseByNamePopup popup) { + return new GotoFileFilter(popup, gotoFileModel, project); } - public void elementChosen(final Object element) { + @Override + public void elementChosen(final ChooseByNamePopup popup, final Object element) { if (element == null) return; ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { @@ -81,7 +80,7 @@ public class GotoFileAction extends GotoActionBase implements DumbAware { } }, ModalityState.NON_MODAL); } - }, ModalityState.current(), true); + }); } protected static class GotoFileFilter extends ChooseByNameFilter { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java index ef2d7197d441..65ac622cf6ba 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java @@ -18,12 +18,12 @@ package com.intellij.ide.actions; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.util.gotoByName.*; -import com.intellij.navigation.NavigationItem; +import com.intellij.lang.Language; import com.intellij.navigation.ChooseByNameRegistry; +import com.intellij.navigation.NavigationItem; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDocumentManager; @@ -32,26 +32,19 @@ public class GotoSymbolAction extends GotoActionBase { public void gotoActionPerformed(AnActionEvent e) { FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.symbol"); final Project project = e.getData(PlatformDataKeys.PROJECT); - - PsiDocumentManager.getInstance(project).commitAllDocuments(); - final GotoSymbolModel2 model = new GotoSymbolModel2(project); - final ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, model, getPsiContext(e), - getInitialText(e.getData(PlatformDataKeys.EDITOR))); - final ChooseByNameFilter filterUI = new ChooseByNameLanguageFilter(popup, model, GotoClassSymbolConfiguration.getInstance(project), - project); - popup.invoke(new ChooseByNamePopupComponent.Callback() { - public void onClose() { - if (GotoSymbolAction.class.equals(myInAction)) { - myInAction = null; - } - filterUI.close(); + PsiDocumentManager.getInstance(project).commitAllDocuments(); + showNavigationPopup(e, model, new GotoActionCallback() { + @Override + protected ChooseByNameFilter createFilter(ChooseByNamePopup popup) { + return new ChooseByNameLanguageFilter(popup, model, GotoClassSymbolConfiguration.getInstance(project), project); } - public void elementChosen(Object element) { + @Override + public void elementChosen(ChooseByNamePopup popup, Object element) { ((NavigationItem)element).navigate(true); } - }, ModalityState.current(), true); + }); } protected boolean hasContributors(DataContext dataContext) { diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index 77a277ac7546..92badac379be 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -311,7 +311,7 @@ public class FileTemplateUtil{ final Properties finalProps = props; CommandProcessor.getInstance().executeCommand(project, new Runnable(){ public void run(){ - final Runnable run = new Runnable(){ + ApplicationManager.getApplication().runWriteAction(new Runnable(){ public void run(){ try{ CreateFromTemplateHandler handler = findHandler(template); @@ -321,8 +321,7 @@ public class FileTemplateUtil{ commandException[0] = ex; } } - }; - ApplicationManager.getApplication().runWriteAction(run); + }); } }, template.isJavaClassTemplate() ? IdeBundle.message("command.create.class.from.template") diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java index b5eba4485b24..c581147a1eaf 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java @@ -74,7 +74,7 @@ import java.util.List; import java.util.Map; -public abstract class AbstractProjectViewPane implements DataProvider, Disposable { +public abstract class AbstractProjectViewPane implements DataProvider, Disposable, BusyObject { public static ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.projectViewPane"); protected final Project myProject; @@ -635,4 +635,9 @@ public abstract class AbstractProjectViewPane implements DataProvider, Disposabl } return false; } + + @Override + public ActionCallback getReady(Object requestor) { + return myTreeBuilder.getUi().getReady(requestor); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 61d5dc90cf70..b72c14c6b5bd 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -116,7 +116,7 @@ import java.util.List; file = "$WORKSPACE_FILE$" )} ) -public final class ProjectViewImpl extends ProjectView implements PersistentStateComponent, Disposable, QuickActionProvider { +public final class ProjectViewImpl extends ProjectView implements PersistentStateComponent, Disposable, QuickActionProvider, BusyObject { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.projectView.impl.ProjectViewImpl"); private final CopyPasteDelegator myCopyPasteDelegator; private boolean isInitialized; @@ -577,6 +577,7 @@ public final class ProjectViewImpl extends ProjectView implements PersistentStat if (toolWindow != null) { final ContentManager contentManager = toolWindow.getContentManager(); final Content content = contentManager.getFactory().createContent(getComponent(), ToolWindowId.PROJECT_VIEW, false); + content.setBusyObject(this); contentManager.addContent(content); content.setPreferredFocusedComponent(new Computable() { @@ -1836,4 +1837,10 @@ public final class ProjectViewImpl extends ProjectView implements PersistentStat ensurePanesLoaded(); return mySelectInTargets.values(); } + + @Override + public ActionCallback getReady(Object requestor) { + AbstractProjectViewPane pane = myId2Pane.get(myCurrentViewSubId); + return pane != null ? pane.getReady(requestor) : new ActionCallback.Done(); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index 169a393956a8..53a2008b05a2 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -447,6 +447,9 @@ public abstract class ChooseByNameBase { case KeyEvent.VK_PAGE_DOWN: ListScrollingUtil.movePageDown(myList); break; + case KeyEvent.VK_TAB: + close(true); + break; case KeyEvent.VK_ENTER: if (myList.getSelectedValue() == EXTRA_ELEM) { myMaximumListSizeLimit += MAXIMUM_LIST_SIZE_LIMIT; @@ -992,7 +995,7 @@ public abstract class ChooseByNameBase { myCompletionKeyStroke = getShortcut(IdeActions.ACTION_CODE_COMPLETION); forwardStroke = getShortcut(IdeActions.ACTION_GOTO_FORWARD); backStroke = getShortcut(IdeActions.ACTION_GOTO_BACK); - + setFocusTraversalKeysEnabled(false); } private KeyStroke getShortcut(String actionCodeCompletion) { diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java index a8d73ba7d634..2f2535ff5e9f 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java @@ -42,8 +42,12 @@ public class IncrementalFindAction extends EditorAction { if (!editor.isOneLineMode()) { final JComponent headerComponent = editor.getHeaderComponent(); if (headerComponent instanceof EditorSearchComponent) { - ((EditorSearchComponent) headerComponent).setInitialText(editor.getSelectionModel().getSelectedText()); - headerComponent.requestFocus(); + if (myReplace) { + ((EditorSearchComponent)headerComponent).replaceCurrent(); + } else { + ((EditorSearchComponent) headerComponent).setInitialText(editor.getSelectionModel().getSelectedText()); + headerComponent.requestFocus(); + } } else { final EditorSearchComponent header = new EditorSearchComponent(editor, project, myReplace); diff --git a/platform/lang-impl/src/com/intellij/packageDependencies/ui/RefactoringScopeElementListenerProvider.java b/platform/lang-impl/src/com/intellij/packageDependencies/ui/RefactoringScopeElementListenerProvider.java index 505ed9dbb175..940cbe6d37c8 100644 --- a/platform/lang-impl/src/com/intellij/packageDependencies/ui/RefactoringScopeElementListenerProvider.java +++ b/platform/lang-impl/src/com/intellij/packageDependencies/ui/RefactoringScopeElementListenerProvider.java @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiQualifiedNamedElement; import com.intellij.psi.search.scope.packageSet.*; +import com.intellij.refactoring.listeners.RefactoringElementAdapter; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.listeners.RefactoringElementListenerComposite; import com.intellij.refactoring.listeners.RefactoringElementListenerProvider; @@ -80,18 +81,9 @@ public class RefactoringScopeElementListenerProvider implements RefactoringEleme if (composite == null) { composite = new RefactoringElementListenerComposite(); } - composite.addListener(new RefactoringElementListener() { + composite.addListener(new RefactoringElementAdapter() { @Override - public void elementMoved(@NotNull PsiElement newElement) { - setName(newElement); - } - - @Override - public void elementRenamed(@NotNull PsiElement newElement) { - setName(newElement); - } - - private void setName(@NotNull PsiElement newElement) { + public void elementRenamedOrMoved(@NotNull PsiElement newElement) { LOG.assertTrue(newElement instanceof PsiQualifiedNamedElement); try { final String newPattern = text.replace(descriptor.getOldQName(), ((PsiQualifiedNamedElement)newElement).getQualifiedName()); diff --git a/platform/lang-impl/src/com/intellij/pom/tree/events/impl/TreeChangeEventImpl.java b/platform/lang-impl/src/com/intellij/pom/tree/events/impl/TreeChangeEventImpl.java index 73f7a5e1f71b..a24983dbd2ff 100644 --- a/platform/lang-impl/src/com/intellij/pom/tree/events/impl/TreeChangeEventImpl.java +++ b/platform/lang-impl/src/com/intellij/pom/tree/events/impl/TreeChangeEventImpl.java @@ -27,6 +27,7 @@ import com.intellij.psi.impl.source.tree.FileElement; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.util.CharTable; import gnu.trove.THashMap; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -40,30 +41,26 @@ public class TreeChangeEventImpl implements TreeChangeEvent{ private final PomModelAspect myAspect; private final FileElement myFileElement; - public TreeChangeEventImpl(PomModelAspect aspect, FileElement treeElement) { + public TreeChangeEventImpl(@NotNull PomModelAspect aspect, @NotNull FileElement treeElement) { myAspect = aspect; myFileElement = treeElement; } + @NotNull public FileElement getRootElement() { return myFileElement; } - public TreeElement[] getChangedElements() { - final TreeElement[] ret = new TreeElement[myChangedElements.size()]; - final Iterator iterator = myChangedInOrder.iterator(); - int index = 0; - while (iterator.hasNext()) { - ret[index++] = (TreeElement)iterator.next(); - } - return ret; + @NotNull + public ASTNode[] getChangedElements() { + return myChangedInOrder.toArray(new ASTNode[myChangedInOrder.size()]); } - public TreeChange getChangesByElement(ASTNode element) { + public TreeChange getChangesByElement(@NotNull ASTNode element) { return myChangedElements.get(element); } - public void addElementaryChange(ASTNode element, ChangeInfo change) { + public void addElementaryChange(@NotNull ASTNode element, @NotNull ChangeInfo change) { final ASTNode parent = element.getTreeParent(); if(parent == null) return; ASTNode currentParent = parent; @@ -99,6 +96,7 @@ public class TreeChangeEventImpl implements TreeChangeEvent{ } public void clear() { + myChangedInOrder.clear(); myChangedElements.clear(); myOfEqualDepth.clear(); } @@ -237,11 +235,12 @@ public class TreeChangeEventImpl implements TreeChangeEvent{ return -1; } + @NotNull public PomModelAspect getAspect() { return myAspect; } - public void merge(PomChangeSet blocked) { + public void merge(@NotNull PomChangeSet blocked) { if(!(blocked instanceof TreeChangeEventImpl)) return; final TreeChangeEventImpl blockedTreeChange = (TreeChangeEventImpl)blocked; final Map changedElements = new HashMap(blockedTreeChange.myChangedElements); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 8424ea6566e1..9da2d00e02b7 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -883,7 +883,14 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF if (tree == null) { IElementType contentElementType = getContentElementType(); if (!(contentElementType instanceof IStubFileElementType)) { - LOG.error("ContentElementType: "+contentElementType+"; file: "+this); + final StringBuilder builder = new StringBuilder(); + builder.append("ContentElementType: ").append(contentElementType).append("; file: ").append(this); + builder.append("\n\t").append("Boolean.TRUE.equals(getUserData(BUILDING_STUB)) = ").append(Boolean.TRUE.equals(getUserData(BUILDING_STUB))); + builder.append("\n\t").append("getTreeElementNoLock() = ").append(getTreeElementNoLock()); + final VirtualFile vFile = getVirtualFile(); + builder.append("\n\t").append("vFile instanceof VirtualFileWithId = ").append(vFile instanceof VirtualFileWithId); + builder.append("\n\t").append("StubUpdatingIndex.canHaveStub(vFile) = ").append(StubUpdatingIndex.canHaveStub(vFile)); + LOG.error(builder.toString()); } final StubElement currentStubTree = ((IStubFileElementType)contentElementType).getBuilder().buildStubTree(this); tree = new StubTree((PsiFileStub)currentStubTree); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java index 4708ab4c5307..b765cb3f1a90 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java @@ -36,6 +36,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.formatter.DocumentBasedFormattingModel; import com.intellij.psi.impl.source.PostprocessReformattingAspect; @@ -188,7 +189,9 @@ public class CodeFormatterFacade { project, mySettings, file.getFileType(), file); FormatterEx formatter = FormatterEx.getInstanceEx(); - formatter.setProgressIndicator(new FormattingProgressIndicatorImpl(project, file, document)); + if (CodeStyleManager.getInstance(project).isSequentialProcessingAllowed()) { + formatter.setProgressIndicator(new FormattingProgressIndicatorImpl(project, file, document)); + } formatter.format(model, mySettings, mySettings.getIndentOptions(file.getFileType()), ranges); for (FormatTextRanges.FormatTextRange range : textRanges) { TextRange textRange = range.getTextRange(); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java index a8ab933f8d24..a6049ecbb69b 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java @@ -48,8 +48,20 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.concurrent.TimeUnit; + public class CodeStyleManagerImpl extends CodeStyleManager { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl"); + private static final ThreadLocal SEQUENTIAL_PROCESSING_ALLOWED + = new ThreadLocal() + { + @Override + protected ProcessingUnderProgressInfo initialValue() { + return new ProcessingUnderProgressInfo(); + } + }; + private final Project myProject; @NonNls private static final String DUMMY_IDENTIFIER = "xxx"; @@ -478,6 +490,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager { document.deleteString(start, end); document.insertString(start, buffer); + setSequentialProcessingAllowed(false); document.insertString(offset, DUMMY_IDENTIFIER); return new TextRange(offset, offset + DUMMY_IDENTIFIER.length()); } @@ -506,6 +519,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager { ASTNode space1 = splitSpaceElement((TreeElement)element, offset - elementStart, charTable); ASTNode marker = Factory.createSingleLeafElement(TokenType.NEW_LINE_INDENT, DUMMY_IDENTIFIER, charTable, file.getManager()); + setSequentialProcessingAllowed(false); parent.addChild(marker, space1.getTreeNext()); PsiElement psiElement = SourceTreeToPsiMap.treeElementToPsi(marker); return psiElement == null ? null : psiElement.getTextRange(); @@ -561,4 +575,55 @@ public class CodeStyleManagerImpl extends CodeStyleManager { private CodeStyleSettings getSettings() { return CodeStyleSettingsManager.getSettings(myProject); } + + @Override + public boolean isSequentialProcessingAllowed() { + return SEQUENTIAL_PROCESSING_ALLOWED.get().isAllowed(); + } + + /** + * Allows to define if {@link #isSequentialProcessingAllowed() sequential processing} should be allowed. + *

+ * Current approach is not allow to stop sequential processing for more than predefine amount of time (couple of seconds). + * That means that call to this method with 'true' argument is not mandatory for successful processing even + * if this method is called with 'false' argument before. + * + * @param allowed flag that defines if {@link #isSequentialProcessingAllowed() sequential processing} should be allowed + */ + public static void setSequentialProcessingAllowed(boolean allowed) { + ProcessingUnderProgressInfo info = SEQUENTIAL_PROCESSING_ALLOWED.get(); + if (allowed) { + info.decrement(); + } + else { + info.increment(); + } + } + + private static class ProcessingUnderProgressInfo { + + private static final long DURATION_TIME = TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS); + + private int myCount; + private long myEndTime; + + public void increment() { + if (myCount > 0 && System.currentTimeMillis() > myEndTime) { + myCount = 0; + } + myCount++; + myEndTime = System.currentTimeMillis() + DURATION_TIME; + } + + public void decrement() { + if (myCount <= 0) { + return; + } + myCount--; + } + + public boolean isAllowed() { + return myCount <= 0 || System.currentTimeMillis() >= myEndTime; + } + } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/AstBufferUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/AstBufferUtil.java index 74714fb932f8..d21f7a81da56 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/AstBufferUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/AstBufferUtil.java @@ -47,13 +47,14 @@ public class AstBufferUtil { @Override public void visitComposite(CompositeElement composite) { - if (element instanceof LazyParseableElement) { - LazyParseableElement lpe = (LazyParseableElement)element; + if (composite instanceof LazyParseableElement) { + LazyParseableElement lpe = (LazyParseableElement)composite; int lpeResult = lpe.copyTo(buffer, result[0]); if (lpeResult > 0) { result[0] = lpeResult; return; } + assert lpe.isParsed(); } super.visitComposite(composite); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java index b27e8c8d0667..b0037f08fc96 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java @@ -154,6 +154,12 @@ public class CompositeElement extends TreeElement { } } + @Nullable + public PsiElement findPsiChildByType(IElementType type) { + final ASTNode node = findChildByType(type); + return node == null ? null : node.getPsi(); + } + public ASTNode findChildByType(IElementType type) { if (DebugUtil.CHECK_INSIDE_ATOMIC_ACTION_ENABLED){ ApplicationManager.getApplication().assertReadAccessAllowed(); @@ -213,8 +219,12 @@ public class CompositeElement extends TreeElement { @NotNull public char[] textToCharArray() { - char[] buffer = new char[getTextLength()]; - walkCopyingText(buffer); + final int len = getTextLength(); + char[] buffer = new char[len]; + final int endOffset = AstBufferUtil.toBuffer(this, buffer, 0); + if (endOffset != len) { + throw new AssertionError("len=" + len + "; endOffset=" + endOffset + "; this=" + this); + } return buffer; } @@ -395,7 +405,7 @@ public class CompositeElement extends TreeElement { catch (AssertionError e) { myCachedLength = NOT_CACHED; String assertion = StringUtil.getThrowableText(e); - LOG.error("Walking failure: ===\n"+assertion+"\n=== Thread dump:\n"+PerformanceWatcher.dumpThreadsToString()+"\n===\n"); + throw new AssertionError("Walking failure: ===\n"+assertion+"\n=== Thread dump:\n"+PerformanceWatcher.dumpThreadsToString()+"\n===\n"); } return myCachedLength; } @@ -426,7 +436,7 @@ public class CompositeElement extends TreeElement { TreeElement cur = this; while (cur != null) { - cur = next(cur, cur.getCachedLength() == NOT_CACHED, true); + cur = next(cur); } if (myCachedLength < 0) { @@ -434,44 +444,36 @@ public class CompositeElement extends TreeElement { } } - private void walkCopyingText(char[] buffer) { - if (TreeUtil.isCollapsedChameleon(this)) { - AstBufferUtil.toBuffer(this, buffer, 0); - return; - } - - int offset = 0; - TreeElement cur = this; - while ((cur = next(cur, cur instanceof CompositeElement && !TreeUtil.isCollapsedChameleon(cur), false)) != null) { - if (cur instanceof LeafElement || TreeUtil.isCollapsedChameleon(cur)) { - offset = AstBufferUtil.toBuffer(cur, buffer, offset); - } - } + void setCachedLength(int cachedLength) { + myCachedLength = cachedLength; } @Nullable - private TreeElement next(TreeElement cur, boolean down, boolean update) { + private TreeElement next(TreeElement cur) { + //for a collapsed chameleon, we're not going down, even if it's expanded by some other thread after this line + final int len = cur.getCachedLength(); + final boolean down = len == NOT_CACHED; if (down) { CompositeElement composite = (CompositeElement)cur; // It's a composite or we won't be going down - TreeElement child = composite.firstChild; + TreeElement child = composite.getFirstChildNode(); // if we're LazyParseable, sync is a must for accessing the non-volatile field if (child != null) { LOG.assertTrue(child.getTreeParent() == composite, cur); return child; } - if (update) { - composite.myCachedLength = 0; - } + composite.myCachedLength = 0; + } else { + assert len >= 0 : this + "; len=" + len; } // up while (cur != this) { CompositeElement parent = cur.getTreeParent(); int curLength = cur.getCachedLength(); - if (update) { - LOG.assertTrue(curLength != NOT_CACHED, cur); - parent.myCachedLength -= curLength; + if (curLength < 0) { + throw new AssertionError(cur + "; " + curLength); } + parent.myCachedLength -= curLength; TreeElement next = cur.getTreeNext(); if (next != null) { @@ -479,10 +481,8 @@ public class CompositeElement extends TreeElement { return next; } - LOG.assertTrue(parent.lastChild == cur, parent); - if (update) { - parent.myCachedLength = -parent.myCachedLength + NOT_CACHED; - } + LOG.assertTrue(parent.getLastChildNode() == cur, parent); + parent.myCachedLength = -parent.myCachedLength + NOT_CACHED; cur = parent; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java index d1838797b7fc..dffd07c0e193 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java @@ -61,6 +61,9 @@ public class LazyParseableElement extends CompositeElement { super(type); synchronized (lock) { myText = text == null ? null : text.toString(); + if (text != null) { + setCachedLength(text.length()); + } } } @@ -104,16 +107,6 @@ public class LazyParseableElement extends CompositeElement { return super.getNotCachedLength(); } - @Override - public int getCachedLength() { - synchronized (lock) { - if (myText != null) { - return myText.length(); - } - } - return super.getCachedLength(); - } - @Override public int hc() { synchronized (lock) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseablePsiElement.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseablePsiElement.java index 863fe6cb66fd..78e8ee6e599d 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseablePsiElement.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseablePsiElement.java @@ -38,7 +38,13 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ReflectionCache; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; public class LazyParseablePsiElement extends LazyParseableElement implements PsiElement, NavigationItem { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.LazyParseablePsiElement"); @@ -52,6 +58,23 @@ public class LazyParseablePsiElement extends LazyParseableElement implements Psi return getChildrenAsPsiElements(null, PsiElementArrayConstructor.PSI_ELEMENT_ARRAY_CONSTRUCTOR); } + @Nullable + protected T findChildByClass(Class aClass) { + for (PsiElement cur = getFirstChild(); cur != null; cur = cur.getNextSibling()) { + if (ReflectionCache.isInstance(cur, aClass)) return (T)cur; + } + return null; + } + + @NotNull + protected T[] findChildrenByClass(Class aClass) { + List result = new ArrayList(); + for (PsiElement cur = getFirstChild(); cur != null; cur = cur.getNextSibling()) { + if (ReflectionCache.isInstance(cur, aClass)) result.add((T)cur); + } + return result.toArray((T[]) Array.newInstance(aClass, result.size())); + } + public PsiElement getFirstChild() { TreeElement child = getFirstChildNode(); if (child == null) return null; diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index d8d71241774e..c2a3e2d99284 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -78,10 +78,19 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(l); if (parserDefinition == null) return false; - final IFileElementType filetype = parserDefinition.getFileNodeType(); - return filetype instanceof IStubFileElementType && - (((IStubFileElementType)filetype).shouldBuildStubFor(file) || - IndexingStamp.isFileIndexed(file, INDEX_ID, IndexInfrastructure.getIndexCreationStamp(INDEX_ID))); + final IFileElementType elementType = parserDefinition.getFileNodeType(); + boolean b = elementType instanceof IStubFileElementType && + (((IStubFileElementType)elementType).shouldBuildStubFor(file) || + IndexingStamp.isFileIndexed(file, INDEX_ID, IndexInfrastructure.getIndexCreationStamp(INDEX_ID))); + if (b) { + String extension = file.getExtension(); + LOG.assertTrue(!"xml".equalsIgnoreCase(extension) && !"tld".equalsIgnoreCase(extension), "File: " + file + + " language: " + l + + " filetype: " + fileType + + " element type: " + elementType + ); + } + return b; } else if (fileType.isBinary()) { final BinaryFileStubBuilder builder = BinaryFileStubBuilders.INSTANCE.forFileType(fileType); diff --git a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java index 666c20317590..c44e92b0c712 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java @@ -33,6 +33,7 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.Ref; @@ -224,7 +225,12 @@ public abstract class BaseRefactoringProcessor { refUsages.set(findUsages()); } }); - final Usage[] usages = UsageInfo2UsageAdapter.convert(refUsages.get()); + final Usage[] usages = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Usage[] compute() { + return UsageInfo2UsageAdapter.convert(refUsages.get()); + } + }); for (Usage usage : usages) { processor.process(usage); diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureGestureDetector.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureGestureDetector.java index 189f15b8742a..0caed03d9f5c 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureGestureDetector.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureGestureDetector.java @@ -199,7 +199,9 @@ public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter impleme if (changeBean != null && changeBean.getInitialText() != null) { final Editor editor = myFileEditorManager.getSelectedTextEditor(); if (editor != null && myTemplateManager.getActiveTemplate(editor) != null) return; - if (LanguageChangeSignatureDetectors.INSTANCE.forLanguage(child.getLanguage()).ignoreChanges(child)) return; + final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(child.getLanguage()); + if (detector == null) return; + if (detector.ignoreChanges(child)) return; final ChangeInfo info = LanguageChangeSignatureDetectors.createCurrentChangeInfo(child, changeBean.getInitialChangeInfo()); if (info == null) { changeBean.reinit(); diff --git a/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java b/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java index bbc2945dac1a..875bee27ff72 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java @@ -38,6 +38,7 @@ import com.intellij.usageView.UsageInfo; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -47,8 +48,8 @@ import java.util.*; @SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) public class GenericInlineHandler { - public static boolean invoke(final PsiElement element, final Editor editor, final InlineHandler languageSpecific) { - final PsiReference invocationReference = TargetElementUtilBase.findReference(editor); + public static boolean invoke(final PsiElement element, @Nullable Editor editor, final InlineHandler languageSpecific) { + final PsiReference invocationReference = editor != null ? TargetElementUtilBase.findReference(editor) : null; final InlineHandler.Settings settings = languageSpecific.prepareInlineElement(element, editor, invocationReference != null); if (settings == null || settings == InlineHandler.Settings.CANNOT_INLINE_SETTINGS) { return settings != null; @@ -65,7 +66,7 @@ public class GenericInlineHandler { public void run() { usagesRef.set(ReferencesSearch.search(element).findAll()); } - }, "Find Usages", false, editor.getProject()); + }, "Find Usages", false, element.getProject()); allReferences = usagesRef.get(); } diff --git a/platform/lang-impl/src/com/intellij/refactoring/inline/InlineRefactoringActionHandler.java b/platform/lang-impl/src/com/intellij/refactoring/inline/InlineRefactoringActionHandler.java index 4bd9427af015..db3ccfa481a9 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/inline/InlineRefactoringActionHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/inline/InlineRefactoringActionHandler.java @@ -38,6 +38,7 @@ import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.util.CommonRefactoringUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -57,6 +58,8 @@ public class InlineRefactoringActionHandler implements RefactoringActionHandler return; } } + + invokeInliner(editor, elements[0]); } public void invoke(@NotNull final Project project, Editor editor, PsiFile file, DataContext dataContext) { @@ -78,7 +81,7 @@ public class InlineRefactoringActionHandler implements RefactoringActionHandler } } - public static boolean invokeInliner(Editor editor, PsiElement element) { + public static boolean invokeInliner(@Nullable Editor editor, PsiElement element) { final List handlers = InlineHandlers.getInlineHandlers(element.getLanguage()); for (InlineHandler handler : handlers) { if (GenericInlineHandler.invoke(element, editor, handler)) { diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java index cd01409972b3..282814b4ab03 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java @@ -32,15 +32,20 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.markup.RangeHighlighter; -import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.editor.markup.*; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.ui.popup.JBPopupAdapter; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.ui.popup.LightweightWindowEvent; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -59,6 +64,7 @@ import com.intellij.refactoring.rename.naming.AutomaticRenamer; import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.TextOccurrencesUtil; +import com.intellij.ui.components.JBList; import com.intellij.usageView.UsageInfo; import com.intellij.util.PairProcessor; import com.intellij.util.containers.MultiMap; @@ -69,7 +75,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.*; +import java.text.MessageFormat; import java.util.*; +import java.util.List; /** * @author ven @@ -136,12 +148,6 @@ public class VariableInplaceRenamer { ourRenamersStack.push(this); - final Map rangesToHighlight = new THashMap(); - //it is crucial to highlight AFTER the template is started, so we collect ranges first - collectElementsToHighlight(rangesToHighlight, refs); - - final HighlightManager highlightManager = HighlightManager.getInstance(myProject); - PsiElement scope = null; final SearchScope searchScope = myElementToRename.getManager().getSearchHelper().getUseScope(myElementToRename); if (searchScope instanceof LocalSearchScope) { @@ -157,22 +163,44 @@ public class VariableInplaceRenamer { if (containingFile == null){ return false; // Should have valid local search scope for inplace rename } + if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, myElementToRename)) return false; + + final List> stringUsages = new ArrayList>(); + final String stringToSearch = myElementToRename.getName(); + if (processTextOccurrences && stringToSearch != null) { + TextOccurrencesUtil + .processUsagesInStringsAndComments(myElementToRename, stringToSearch, true, new PairProcessor() { + public boolean process(PsiElement psiElement, TextRange textRange) { + stringUsages.add(Pair.create(psiElement, textRange)); + return true; + } + }); + } + if (stringUsages.isEmpty()) { + runRenameTemplate(nameSuggestions, refs, stringUsages, scope, containingFile); + } else { + new RenameChooser(myEditor).showChooser(refs, stringUsages, nameSuggestions, scope, containingFile); + } + + myEditor.putUserData(INPLACE_RENAMER, this); + return true; + } + + private void runRenameTemplate(LinkedHashSet nameSuggestions, + Collection refs, + Collection> stringUsages, + PsiElement scope, + final PsiFile containingFile) { final PsiElement context = containingFile.getContext(); if (context != null) { scope = context.getContainingFile(); } - String stringToSearch = myElementToRename.getName(); - if (processTextOccurrences && - stringToSearch != null && - !TextOccurrencesUtil.processUsagesInStringsAndComments(myElementToRename, stringToSearch, true, new PairProcessor() { - public boolean process(PsiElement psiElement, TextRange textRange) { - return false; - } - })) { - return false; - } + final Map rangesToHighlight = new THashMap(); + //it is crucial to highlight AFTER the template is started, so we collect ranges first + collectElementsToHighlight(rangesToHighlight, refs, stringUsages); + final HighlightManager highlightManager = HighlightManager.getInstance(myProject); ResolveSnapshotProvider resolveSnapshotProvider = INSTANCE.forLanguage(scope.getLanguage()); final ResolveSnapshotProvider.ResolveSnapshot snapshot = resolveSnapshotProvider != null ? resolveSnapshotProvider.createSnapshot(scope):null; @@ -181,12 +209,14 @@ public class VariableInplaceRenamer { PsiElement nameIdentifier = myElementToRename instanceof PsiNameIdentifierOwner ? ((PsiNameIdentifierOwner)myElementToRename).getNameIdentifier() : null; int offset = myEditor.getCaretModel().getOffset(); PsiElement selectedElement = getSelectedInEditorElement(nameIdentifier, refs, offset); - if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, myElementToRename)) return true; if (nameIdentifier != null) addVariable(nameIdentifier, selectedElement, builder, nameSuggestions); for (PsiReference ref : refs) { addVariable(ref, selectedElement, builder, offset, nameSuggestions); } + for (Pair usage : stringUsages) { + addVariable(usage.first, usage.second, builder); + } addAdditionalVariables(builder); final PsiElement scope1 = scope; @@ -196,6 +226,8 @@ public class VariableInplaceRenamer { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { final int offset = myEditor.getCaretModel().getOffset(); + final SelectionModel selectionModel = myEditor.getSelectionModel(); + final TextRange selectedRange = preserveSelectedRange(selectionModel); Template template = builder.buildInlineTemplate(); template.setToShortenLongNames(false); TextRange range = scope1.getTextRange(); @@ -227,7 +259,8 @@ public class VariableInplaceRenamer { public void templateFinished(Template template, boolean brokenOff) { super.templateFinished(template, brokenOff); if (myNewName != null) { - performAutomaticRename(myNewName, PsiTreeUtil.getParentOfType(containingFile.findElementAt(renameOffset), PsiNameIdentifierOwner.class)); + performAutomaticRename(myNewName, PsiTreeUtil.getParentOfType(containingFile.findElementAt(renameOffset), + PsiNameIdentifierOwner.class)); } moveOffsetAfter(true); } @@ -242,6 +275,9 @@ public class VariableInplaceRenamer { Runnable runnable = new Runnable() { public void run() { myEditor.getCaretModel().moveToOffset(offset); + if (selectedRange != null){ + myEditor.getSelectionModel().setSelection(selectedRange.getStartOffset(), selectedRange.getEndOffset()); + } } }; @@ -262,8 +298,14 @@ public class VariableInplaceRenamer { } }, RefactoringBundle.message("rename.title"), null); - myEditor.putUserData(INPLACE_RENAMER, this); - return true; + } + + @Nullable + protected TextRange preserveSelectedRange(SelectionModel selectionModel) { + if (selectionModel.hasSelection()) { + return new TextRange(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); + } + return null; } protected void moveOffsetAfter(boolean success) { @@ -356,7 +398,9 @@ public class VariableInplaceRenamer { } } - private void collectElementsToHighlight(Map rangesToHighlight, Collection refs) { + private void collectElementsToHighlight(Map rangesToHighlight, + Collection refs, + Collection> stringUsages) { EditorColorsManager colorsManager = EditorColorsManager.getInstance(); if (myElementToRename instanceof PsiNameIdentifierOwner) { PsiElement nameId = ((PsiNameIdentifierOwner)myElementToRename).getNameIdentifier(); @@ -379,6 +423,12 @@ public class VariableInplaceRenamer { EditorColors.SEARCH_RESULT_ATTRIBUTES); rangesToHighlight.put(range, attributes); } + + for (Pair usage : stringUsages) { + final TextRange range = usage.second.shiftRight(usage.first.getTextOffset()); + final TextAttributes attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); + rangesToHighlight.put(range, attributes); + } } private static void addHighlights(@NotNull Map ranges, @NotNull Editor editor, @NotNull Collection highlighters, @NotNull HighlightManager highlightManager) { @@ -441,6 +491,12 @@ public class VariableInplaceRenamer { } } + private static void addVariable(PsiElement element, + TextRange textRange, + TemplateBuilderImpl builder) { + builder.replaceElement(element, textRange, OTHER_VARIABLE_NAME, PRIMARY_VARIABLE_NAME, false); + } + protected LookupElement[] createLookupItems(final LookupElement[] lookupItems, final String name) { return lookupItems; } @@ -486,4 +542,85 @@ public class VariableInplaceRenamer { return myAdvertisementText; } } + + private class RenameChooser { + @NonNls private static final String CODE_OCCURRENCES = "Rename code occurrences"; + @NonNls private static final String ALL_OCCURRENCES = "Rename all occurrences"; + private final Set myRangeHighlighters = new HashSet(); + private final Editor myEditor; + private final TextAttributes myAttributes; + + public RenameChooser(Editor editor) { + myEditor = editor; + myAttributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); + } + + public void showChooser(final Collection refs, + final Collection> stringUsages, + final LinkedHashSet nameSuggestions, + final PsiElement scope, + final PsiFile containingFile) { + + final DefaultListModel model = new DefaultListModel(); + model.addElement(CODE_OCCURRENCES); + model.addElement(ALL_OCCURRENCES); + final JList list = new JBList(model); + + list.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(final ListSelectionEvent e) { + final String selectedValue = (String)list.getSelectedValue(); + if (selectedValue == null) return; + dropHighlighters(); + final MarkupModel markupModel = myEditor.getMarkupModel(); + + if (selectedValue == ALL_OCCURRENCES) { + for (Pair pair : stringUsages) { + final TextRange textRange = pair.second.shiftRight(pair.first.getTextOffset()); + final RangeHighlighter rangeHighlighter = markupModel.addRangeHighlighter( + textRange.getStartOffset(), textRange.getEndOffset(), HighlighterLayer.SELECTION - 1, myAttributes, + HighlighterTargetArea.EXACT_RANGE); + myRangeHighlighters.add(rangeHighlighter); + } + } + + for (PsiReference reference : refs) { + final PsiElement element = reference.getElement(); + if (element == null) continue; + final TextRange textRange = element.getTextRange(); + final RangeHighlighter rangeHighlighter = markupModel.addRangeHighlighter( + textRange.getStartOffset(), textRange.getEndOffset(), HighlighterLayer.SELECTION - 1, myAttributes, + HighlighterTargetArea.EXACT_RANGE); + myRangeHighlighters.add(rangeHighlighter); + } + } + }); + + JBPopupFactory.getInstance().createListPopupBuilder(list) + .setTitle("String occurrences found") + .setMovable(false) + .setResizable(false) + .setRequestFocus(true) + .setItemChoosenCallback(new Runnable() { + public void run() { + runRenameTemplate(nameSuggestions, refs, list.getSelectedValue() == ALL_OCCURRENCES ? stringUsages : new ArrayList>(), scope, containingFile); + } + }) + .addListener(new JBPopupAdapter() { + @Override + public void onClosed(LightweightWindowEvent event) { + dropHighlighters(); + } + }) + .createPopup().showInBestPositionFor(myEditor); + } + + + + private void dropHighlighters() { + for (RangeHighlighter highlight : myRangeHighlighters) { + highlight.dispose(); + } + myRangeHighlighters.clear(); + } + } } diff --git a/platform/lang-impl/src/com/intellij/ui/debugger/extensions/DisposerDebugger.java b/platform/lang-impl/src/com/intellij/ui/debugger/extensions/DisposerDebugger.java index 87b2d994847e..d368803099ad 100644 --- a/platform/lang-impl/src/com/intellij/ui/debugger/extensions/DisposerDebugger.java +++ b/platform/lang-impl/src/com/intellij/ui/debugger/extensions/DisposerDebugger.java @@ -25,6 +25,7 @@ import com.intellij.ide.util.treeView.NodeDescriptor; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; @@ -204,8 +205,7 @@ public class DisposerDebugger implements UiDebuggerExtension, Disposable { public void actionPerformed(AnActionEvent e) { try { - Toolkit.getDefaultToolkit().getSystemClipboard() - .setContents(new TextTransferrable(myAllocation.getText(), myAllocation.getText()), null); + CopyPasteManager.getInstance().setContents(new TextTransferrable(myAllocation.getText(), myAllocation.getText())); } catch (HeadlessException e1) { LOG.error(e1); diff --git a/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceUtil.java b/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceUtil.java index 6bd6c5712f35..1f77a3107745 100644 --- a/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceUtil.java +++ b/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceUtil.java @@ -22,7 +22,6 @@ import com.intellij.execution.executors.DefaultRunExecutor; import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.TextConsoleBuilder; import com.intellij.execution.filters.TextConsoleBuilderFactory; -import com.intellij.execution.impl.ConsoleViewImpl; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.ui.ExecutionConsole; @@ -67,7 +66,7 @@ public class AnalyzeStacktraceUtil { @Nullable public static String getTextInClipboard() { - final Transferable contents = CopyPasteManagerEx.getInstanceEx().getSystemClipboardContents(false); + final Transferable contents = CopyPasteManagerEx.getInstanceEx().getSystemClipboardContents(); if (contents != null) { try { return (String)contents.getTransferData(DataFlavor.stringFlavor); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index d54a659b2deb..2b4cdc78d3f5 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -101,13 +101,7 @@ public class FileBasedIndex implements ApplicationComponent { private final Set> myNotRequiringContentIndices = new HashSet>(); private final Set myNoLimitCheckTypes = new HashSet(); - private final PerIndexDocumentMap myLastIndexedDocStamps = new PerIndexDocumentMap() { - @Override - protected Long createDefault(Document document) { - return 0L; - } - }; - + private final PerIndexDocumentVersionMap myLastIndexedDocStamps = new PerIndexDocumentVersionMap(); private final ChangedFilesCollector myChangedFilesCollector; private final List myIndexableSets = ContainerUtil.createEmptyCOWList(); @@ -353,7 +347,6 @@ public class FileBasedIndex implements ApplicationComponent { * @param isCurrentVersionCorrupted */ private boolean registerIndexer(final FileBasedIndexExtension extension, final boolean isCurrentVersionCorrupted) throws IOException { - boolean versionChanged = false; final ID name = extension.getName(); final int version = extension.getVersion(); if (!extension.dependsOnFileContent()) { @@ -362,6 +355,7 @@ public class FileBasedIndex implements ApplicationComponent { myIndexIdToVersionMap.put(name, version); final File versionFile = IndexInfrastructure.getVersionFile(name); final boolean versionFileExisted = versionFile.exists(); + boolean versionChanged = false; if (isCurrentVersionCorrupted || IndexInfrastructure.versionDiffers(versionFile, version)) { if (!isCurrentVersionCorrupted && versionFileExisted) { versionChanged = true; @@ -1042,7 +1036,7 @@ public class FileBasedIndex implements ApplicationComponent { private void clearIndex(final ID indexId) throws StorageException { final UpdatableIndex index = getIndex(indexId); - assert index != null; + assert index != null: "Index with key " + indexId + " not found or not registered properly"; index.clear(); try { IndexInfrastructure.rewriteVersion(IndexInfrastructure.getVersionFile(indexId), myIndexIdToVersionMap.get(indexId)); @@ -1161,7 +1155,7 @@ public class FileBasedIndex implements ApplicationComponent { } // returns false if doc was not indexed because the file does not fit in scope - private boolean indexUnsavedDocument(final Document document, final ID requestedIndexId, final Project project, GlobalSearchScope filter) throws StorageException { + private boolean indexUnsavedDocument(@NotNull final Document document, @NotNull final ID requestedIndexId, final Project project, GlobalSearchScope filter) throws StorageException { final VirtualFile vFile = myFileDocumentManager.getFile(document); if (!(vFile instanceof VirtualFileWithId) || !vFile.isValid()) { return true; @@ -1180,7 +1174,7 @@ public class FileBasedIndex implements ApplicationComponent { } final long currentDocStamp = content.getModificationStamp(); - if (currentDocStamp != myLastIndexedDocStamps.getAndSet(document, requestedIndexId, currentDocStamp).longValue()) { + if (currentDocStamp != myLastIndexedDocStamps.getAndSet(document, requestedIndexId, currentDocStamp)) { final Ref exRef = new Ref(null); ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { public void run() { @@ -1253,9 +1247,7 @@ public class FileBasedIndex implements ApplicationComponent { } private void cleanupMemoryStorage() { - synchronized (myLastIndexedDocStamps) { - myLastIndexedDocStamps.clear(); - } + myLastIndexedDocStamps.clear(); for (ID indexId : myIndices.keySet()) { final MapReduceIndex index = (MapReduceIndex)getIndex(indexId); assert index != null; @@ -1562,7 +1554,6 @@ public class FileBasedIndex implements ApplicationComponent { IndexingStamp.flushCache(); final List> affectedIndices = new ArrayList>(myIndices.size()); - Boolean isTooLarge = null; for (final ID indexId : myIndices.keySet()) { try { if (!needsFileContentLoading(indexId)) { @@ -1572,12 +1563,7 @@ public class FileBasedIndex implements ApplicationComponent { } else { // the index requires file content if (shouldUpdateIndex(file, indexId)) { - if (isTooLarge == null) { - isTooLarge = Boolean.valueOf(isTooLarge(file)); - } - if (!isTooLarge.booleanValue()) { - affectedIndices.add(indexId); - } + affectedIndices.add(indexId); } } } @@ -1588,7 +1574,7 @@ public class FileBasedIndex implements ApplicationComponent { } if (!affectedIndices.isEmpty()) { - if (markForReindex) { + if (markForReindex && !isTooLarge(file)) { // only mark the file as unindexed, reindex will be done lazily ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { @@ -1771,10 +1757,10 @@ public class FileBasedIndex implements ApplicationComponent { if (file instanceof VirtualFileWithId) { try { - boolean oldStuff = true; if (file instanceof NewVirtualFile) { file.putUserData(NewVirtualFile.FILE_TYPE_KEY, file.getFileType()); } + boolean oldStuff = true; if (!isTooLarge(file)) { for (ID indexId : myIndices.keySet()) { try { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/PerIndexDocumentMap.java b/platform/lang-impl/src/com/intellij/util/indexing/PerIndexDocumentMap.java deleted file mode 100644 index 06c42bdb001b..000000000000 --- a/platform/lang-impl/src/com/intellij/util/indexing/PerIndexDocumentMap.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.util.indexing; - -import com.intellij.openapi.editor.Document; -import com.intellij.util.containers.ConcurrentFactoryMap; -import com.intellij.util.containers.ConcurrentWeakFactoryMap; - -import java.util.Map; - -/** - * @author Dmitry Avdeev - * @author peter - */ -public abstract class PerIndexDocumentMap { - - private final Map> myVersions = new ConcurrentWeakFactoryMap>() { - protected Map create(final Document document) { - return new ConcurrentFactoryMap() { - protected T create(ID key) { - return createDefault(document); - } - }; - } - }; - - public T get(Document document, ID indexId) { - return myVersions.get(document).get(indexId); - } - - public void put(Document document, ID indexId, T value) { - myVersions.get(document).put(indexId, value); - } - - public synchronized T getAndSet(Document document, ID indexId, T value) { - T old = get(document, indexId); - put(document, indexId, value); - return old; - } - - public void clear() { - myVersions.clear(); - } - - protected abstract T createDefault(Document document); -} diff --git a/platform/lang-impl/src/com/intellij/util/indexing/PerIndexDocumentVersionMap.java b/platform/lang-impl/src/com/intellij/util/indexing/PerIndexDocumentVersionMap.java new file mode 100644 index 000000000000..316e114b1dbe --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/PerIndexDocumentVersionMap.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2011 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.util.indexing; + +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.UserDataHolderEx; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Dmitry Avdeev + * @author peter + */ +public class PerIndexDocumentVersionMap { + private volatile int mapVersion; + private static class IdVersionInfo { + private final ID id; + private int mapVersion; + private long docVersion; + + private IdVersionInfo(@NotNull ID id, long docVersion, int mapVersion) { + this.docVersion = docVersion; + this.mapVersion = mapVersion; + this.id = id; + } + } + + private static final Key> KEY = Key.create("UnsavedDocIdVersionInfo"); + public long getAndSet(@NotNull Document document, @NotNull ID indexId, long value) { + List list = document.getUserData(KEY); + if (list == null) { + list = ((UserDataHolderEx)document).putUserDataIfAbsent(KEY, new ArrayList()); + } + + synchronized (list) { + for (IdVersionInfo info : list) { + if (info.id == indexId) { + long old = info.docVersion; + if (info.mapVersion != mapVersion) { + old = 0; + info.mapVersion = mapVersion; + } + info.docVersion = value; + return old; + } + } + list.add(new IdVersionInfo(indexId, value, mapVersion)); + return 0; + } + } + + public void clear() { + mapVersion++; + } +} diff --git a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java index d9bab877244f..d7045bf2f917 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java @@ -28,7 +28,9 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; -import java.util.*; +import java.util.Iterator; +import java.util.List; +import java.util.Map; public class GeneralCommandLine { private Map myEnvParams; @@ -62,11 +64,6 @@ public class GeneralCommandLine { myCharset = charset; } - public void setCharsetAndAddJavaParameter(@NotNull Charset charset) { - myCharset = charset; - addParameter("-Dfile.encoding=" + charset.name()); - } - public void addParameters(final String... parameters) { for (String parameter : parameters) { addParameter(parameter); diff --git a/platform/platform-api/src/com/intellij/execution/process/ProcessHandler.java b/platform/platform-api/src/com/intellij/execution/process/ProcessHandler.java index f75ccb40cf4c..d1976a2804bd 100644 --- a/platform/platform-api/src/com/intellij/execution/process/ProcessHandler.java +++ b/platform/platform-api/src/com/intellij/execution/process/ProcessHandler.java @@ -15,10 +15,8 @@ */ package com.intellij.execution.process; -import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.util.concurrency.Semaphore; @@ -26,7 +24,6 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; import java.io.OutputStream; -import java.lang.ref.WeakReference; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; @@ -36,6 +33,10 @@ import java.util.concurrent.atomic.AtomicInteger; public abstract class ProcessHandler extends UserDataHolderBase { private static final Logger LOG = Logger.getInstance("#com.intellij.execution.process.ProcessHandler"); + /** + * todo: replace with an overridable method [nik] + * @deprecated + */ public static final Key SILENTLY_DESTROY_ON_CLOSE = Key.create("SILENTLY_DESTROY_ON_CLOSE"); private final List myListeners = ContainerUtil.createEmptyCOWList(); diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUpdater.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUpdater.java index c076a99d3013..a6bfe1507455 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUpdater.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUpdater.java @@ -86,7 +86,7 @@ public class AbstractTreeUpdater implements Disposable, Activatable { } public boolean hasNodesToUpdate() { - return myNodeQueue.size() > 0 || !myUpdateQueue.isEmpty(); + return !myNodeQueue.isEmpty() || !myUpdateQueue.isEmpty(); } public void dispose() { @@ -114,15 +114,15 @@ public class AbstractTreeUpdater implements Disposable, Activatable { toAdd.expire(); break; } - else if (passInQueue.getNode() == toAdd.getNode()) { + if (passInQueue.getNode() == toAdd.getNode()) { toAdd.expire(); break; } - else if (toAdd.getNode().isNodeAncestor(passInQueue.getNode())) { + if (toAdd.getNode().isNodeAncestor(passInQueue.getNode())) { toAdd.expire(); break; } - else if (passInQueue.getNode().isNodeAncestor(toAdd.getNode())) { + if (passInQueue.getNode().isNodeAncestor(toAdd.getNode())) { iterator.remove(); passInQueue.expire(); } @@ -133,9 +133,7 @@ public class AbstractTreeUpdater implements Disposable, Activatable { if (!toAdd.isExpired()) { final Collection yielding = ui.getYeildingPasses(); - for (Iterator iterator = yielding.iterator(); iterator.hasNext();) { - TreeUpdatePass eachYielding = iterator.next(); - + for (TreeUpdatePass eachYielding : yielding) { final DefaultMutableTreeNode eachNode = eachYielding.getCurrentNode(); if (eachNode != null) { if (eachNode.isNodeAncestor(toAdd.getNode())) { @@ -228,8 +226,7 @@ public class AbstractTreeUpdater implements Disposable, Activatable { try { myTreeBuilder.getUi().updateSubtreeNow(eachPass, false); } - catch (ProcessCanceledException e) { - return; + catch (ProcessCanceledException ignored) { } } }); @@ -348,10 +345,8 @@ public class AbstractTreeUpdater implements Disposable, Activatable { } public boolean isEnqueuedToUpdate(DefaultMutableTreeNode node) { - Iterator nodes = myNodeQueue.iterator(); - while (nodes.hasNext()) { - TreeUpdatePass each = nodes.next(); - if (each.willUpdate(node)) return true; + for (TreeUpdatePass pass : myNodeQueue) { + if (pass.willUpdate(node)) return true; } return false; } diff --git a/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java b/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java index 92505fe844d9..9f4acb282a6b 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java @@ -26,7 +26,6 @@ import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.Nullable; -import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; @@ -166,16 +165,7 @@ public class EditorModificationUtil { } private static Transferable getClipboardContent(Editor editor) { - Transferable content; - Project project = editor.getProject(); - - if (project != null) { - content = CopyPasteManager.getInstance().getContents(); - } else { - Clipboard clipboard = editor.getComponent().getToolkit().getSystemClipboard(); - content = clipboard.getContents(editor.getComponent()); - } - return content; + return CopyPasteManager.getInstance().getContents(); } public static void pasteFromClipboardAsBlock(Editor editor) { diff --git a/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java b/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java index ea7beabfed99..d9a9b532eaab 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java @@ -27,7 +27,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.WeakList; import org.jetbrains.annotations.NotNull; -import java.util.Iterator; +import java.util.ArrayList; +import java.util.List; /** * Date: Mar 17, 2009 @@ -39,14 +40,16 @@ public class LazyRangeMarkerFactory extends AbstractProjectComponent { super(project); EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentAdapter() { public void beforeDocumentChange(DocumentEvent e) { - for (Iterator it = myMarkers.iterator(); it.hasNext();) { - final LazyMarker marker = it.next(); + List markers = myMarkers.toStrongList(); + List markersToRemove = new ArrayList(); + for (final LazyMarker marker : markers) { final VirtualFile docFile = fileDocumentManager.getFile(e.getDocument()); if (marker.getFile() == docFile) { marker.ensureDelegate(); - it.remove(); + markersToRemove.add(marker); } } + myMarkers.removeAll(markersToRemove); } }, project); } diff --git a/platform/platform-api/src/com/intellij/openapi/fileTypes/FileTypeConsumer.java b/platform/platform-api/src/com/intellij/openapi/fileTypes/FileTypeConsumer.java index 14452f17dcdf..6d776101c448 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileTypes/FileTypeConsumer.java +++ b/platform/platform-api/src/com/intellij/openapi/fileTypes/FileTypeConsumer.java @@ -25,6 +25,8 @@ import org.jetbrains.annotations.Nullable; public interface FileTypeConsumer { String EXTENSION_DELIMITER = ";"; + void consume(final @NotNull FileType fileType); + void consume(final @NotNull FileType fileType, @NonNls final String extensions); void consume(final @NotNull FileType fileType, final FileNameMatcher... matchers); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsStateService.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsStateService.java index 6bd41e819a80..a76d2cf819f2 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsStateService.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsStateService.java @@ -62,7 +62,9 @@ public class MasterDetailsStateService implements PersistentStateComponent stateClass) { ComponentState state = myStates.get(key); - return state != null ? XmlSerializer.deserialize(state.mySettings, stateClass) : null; + if (state == null) return null; + final Element settings = state.mySettings; + return settings != null ? XmlSerializer.deserialize(settings, stateClass) : null; } public void setComponentState(@NotNull @NonNls String key, @NotNull MasterDetailsState state) { diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindow.java b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindow.java index 12aca9181a42..93870283c6ce 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindow.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindow.java @@ -16,6 +16,7 @@ package com.intellij.openapi.wm; import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.util.BusyObject; import com.intellij.openapi.util.Key; import com.intellij.ui.content.ContentManager; import org.jetbrains.annotations.NotNull; @@ -26,7 +27,7 @@ import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.InputEvent; -public interface ToolWindow { +public interface ToolWindow extends BusyObject { Key SHOW_CONTENT_ICON = new Key("ContentIcon"); diff --git a/platform/platform-api/src/com/intellij/ui/AutoScrollToSourceHandler.java b/platform/platform-api/src/com/intellij/ui/AutoScrollToSourceHandler.java index fa9496738462..d42881301d22 100644 --- a/platform/platform-api/src/com/intellij/ui/AutoScrollToSourceHandler.java +++ b/platform/platform-api/src/com/intellij/ui/AutoScrollToSourceHandler.java @@ -25,8 +25,11 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.util.BusyObject; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindow; import com.intellij.pom.Navigatable; import com.intellij.util.Alarm; import com.intellij.util.OpenSourceUtil; @@ -140,22 +143,28 @@ public abstract class AutoScrollToSourceHandler { protected abstract boolean isAutoScrollMode(); protected abstract void setAutoScrollMode(boolean state); - protected void scrollToSource(Component tree) { + protected void scrollToSource(final Component tree) { DataContext dataContext=DataManager.getInstance().getDataContext(tree); - final VirtualFile vFile = PlatformDataKeys.VIRTUAL_FILE.getData(dataContext); - if (vFile != null) { - // Attempt to navigate to the virtual file with unknown file type will show a modal dialog - // asking to register some file type for this file. This behaviour is undesirable when autoscrolling. - if (FileTypeManager.getInstance().getFileTypeByFile(vFile) == FileTypes.UNKNOWN) return; - } - Navigatable[] navigatables = PlatformDataKeys.NAVIGATABLE_ARRAY.getData(dataContext); - if (navigatables != null) { - for (Navigatable navigatable : navigatables) { - // we are not going to open modal dialog during autoscrolling - if (!navigatable.canNavigateToSource()) return; + getReady(dataContext).doWhenDone(new Runnable() { + @Override + public void run() { + DataContext context = DataManager.getInstance().getDataContext(tree); + final VirtualFile vFile = PlatformDataKeys.VIRTUAL_FILE.getData(context); + if (vFile != null) { + // Attempt to navigate to the virtual file with unknown file type will show a modal dialog + // asking to register some file type for this file. This behaviour is undesirable when autoscrolling. + if (FileTypeManager.getInstance().getFileTypeByFile(vFile) == FileTypes.UNKNOWN) return; + } + Navigatable[] navigatables = PlatformDataKeys.NAVIGATABLE_ARRAY.getData(context); + if (navigatables != null) { + for (Navigatable navigatable : navigatables) { + // we are not going to open modal dialog during autoscrolling + if (!navigatable.canNavigateToSource()) return; + } + } + OpenSourceUtil.openSourcesFrom(context, false); } - } - OpenSourceUtil.openSourcesFrom(dataContext, false); + }); } public ToggleAction createToggleAction() { @@ -175,5 +184,10 @@ public abstract class AutoScrollToSourceHandler { setAutoScrollMode(flag); } } + + private ActionCallback getReady(DataContext context) { + ToolWindow toolWindow = PlatformDataKeys.TOOL_WINDOW.getData(context); + return toolWindow != null ? toolWindow.getReady(this) : new ActionCallback.Done(); + } } diff --git a/platform/platform-api/src/com/intellij/ui/components/JBLabel.java b/platform/platform-api/src/com/intellij/ui/components/JBLabel.java new file mode 100644 index 000000000000..952d6ba96628 --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/components/JBLabel.java @@ -0,0 +1,91 @@ +/* + * Copyright 2000-2011 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.ui.components; + +import com.intellij.openapi.util.SystemInfo; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; + +public class JBLabel extends JLabel { + private Style myStyle = Style.REGULAR; + + public enum Style {REGULAR, SMALL} + + public JBLabel() { + } + + public JBLabel(@NotNull Style style) { + setStyle(style); + } + + public JBLabel(@Nullable Icon image) { + super(image); + } + + public JBLabel(@NotNull String text) { + super(text); + } + + public JBLabel(@NotNull String text, @NotNull Style style) { + super(text); + setStyle(style); + } + + public JBLabel(@NotNull String text, int horizontalAlignment) { + super(text, horizontalAlignment); + } + + public JBLabel(@Nullable Icon image, int horizontalAlignment) { + super(image, horizontalAlignment); + } + + public JBLabel(@NotNull String text, @Nullable Icon icon, int horizontalAlignment) { + super(text, icon, horizontalAlignment); + } + + public void setStyle(@NotNull Style style) { + myStyle = style; + + if (SystemInfo.isMac) { + putClientProperty("JComponent.sizeVariant", style == Style.REGULAR ? "regular" : "small"); + } + else { + Font defFont = UIUtil.getLabelFont(); + Font font = getFont(); + if (style == JBLabel.Style.REGULAR) { + if (font != null) { + setFont(font.deriveFont(defFont.getSize())); + } + } + else { + if (font == null) font = defFont; + setFont(font.deriveFont(defFont.getSize() * 0.8f)); + } + } + Container p = getParent(); + if (p != null) { + SwingUtilities.updateComponentTreeUI(p); + } + } + + public Style getStyle() { + return myStyle; + } +} diff --git a/platform/platform-api/src/com/intellij/ui/content/Content.java b/platform/platform-api/src/com/intellij/ui/content/Content.java index e0b134bcccd6..68c6d96ace9c 100644 --- a/platform/platform-api/src/com/intellij/ui/content/Content.java +++ b/platform/platform-api/src/com/intellij/ui/content/Content.java @@ -18,6 +18,7 @@ package com.intellij.ui.content; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.ui.ComponentContainer; +import com.intellij.openapi.util.BusyObject; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.UserDataHolder; import org.jetbrains.annotations.NonNls; @@ -102,5 +103,9 @@ public interface Content extends UserDataHolder, ComponentContainer { @Nullable AlertIcon getAlertIcon(); void fireAlert(); - + + @Nullable + BusyObject getBusyObject(); + void setBusyObject(BusyObject object); + } diff --git a/platform/platform-api/src/com/intellij/ui/content/ContentManager.java b/platform/platform-api/src/com/intellij/ui/content/ContentManager.java index 75dbc3a17ac6..f3668b2da457 100644 --- a/platform/platform-api/src/com/intellij/ui/content/ContentManager.java +++ b/platform/platform-api/src/com/intellij/ui/content/ContentManager.java @@ -19,13 +19,14 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.util.BusyObject; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.List; -public interface ContentManager extends Disposable { +public interface ContentManager extends Disposable, BusyObject { boolean canCloseContents(); diff --git a/platform/platform-api/src/com/intellij/ui/tabs/TabsListener.java b/platform/platform-api/src/com/intellij/ui/tabs/TabsListener.java index 08888ee75160..ee3bc4a8f2af 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/TabsListener.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/TabsListener.java @@ -15,7 +15,10 @@ */ package com.intellij.ui.tabs; +import com.intellij.util.messages.Topic; + public interface TabsListener { + Topic TOPIC = Topic.create("TabsListener", TabsListener.class); void selectionChanged(TabInfo oldSelection, TabInfo newSelection); diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java index ef1716c324ca..12aaa3da4acd 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java @@ -243,7 +243,9 @@ public class JBTabsImpl extends JComponent new LazyUiDisposable(parent, this, this) { protected void initialize(@NotNull Disposable parent, @NotNull JBTabsImpl child, @Nullable Project project) { - myProject = project; + if (project != null) { + myProject = project; + } Disposer.register(child, myAnimator); Disposer.register(child, new Disposable() { @@ -793,6 +795,9 @@ public class JBTabsImpl extends JComponent private void fireSelectionChanged(TabInfo oldInfo, TabInfo newInfo) { if (oldInfo != newInfo) { + if (myProject != null) { + myProject.getMessageBus().syncPublisher(TabsListener.TOPIC).selectionChanged(oldInfo, newInfo); + } for (TabsListener eachListener : myTabListeners) { if (eachListener != null) { eachListener.selectionChanged(oldInfo, newInfo); diff --git a/platform/platform-api/src/com/intellij/util/ui/ErrorTreeView.java b/platform/platform-api/src/com/intellij/util/ui/ErrorTreeView.java index f069ba016658..1870e7b4011b 100644 --- a/platform/platform-api/src/com/intellij/util/ui/ErrorTreeView.java +++ b/platform/platform-api/src/com/intellij/util/ui/ErrorTreeView.java @@ -19,6 +19,8 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -29,12 +31,35 @@ public interface ErrorTreeView extends Disposable { /** * If file is not null, allows to navigate to this file, line, column */ - void addMessage(int type, String[] text, VirtualFile file, int line, int column, Object data); + void addMessage(int type, + @NotNull String[] text, + @Nullable VirtualFile file, + int line, + int column, + @Nullable Object data); + + /** + * Allows adding messages related to other files under 'underFileGroup' + */ + void addMessage(int type, + @NotNull String[] text, + @Nullable VirtualFile underFileGroup, + @Nullable VirtualFile file, + int line, + int column, + @Nullable Object data); /** * add message, allowing navigation via custom Navigatable object */ - void addMessage(int type, String[] text, String groupName, Navigatable navigatable, String exportTextPrefix, String rendererTextPrefix, Object data); + void addMessage(int type, + @NotNull String[] text, + @NotNull String groupName, + @NotNull Navigatable navigatable, + @Nullable String exportTextPrefix, + @Nullable String rendererTextPrefix, + @Nullable Object data); + @NotNull JComponent getComponent(); } diff --git a/platform/platform-api/src/com/intellij/util/ui/update/MergingUpdateQueue.java b/platform/platform-api/src/com/intellij/util/ui/update/MergingUpdateQueue.java index bcb2e34055f7..c6fec60254d8 100644 --- a/platform/platform-api/src/com/intellij/util/ui/update/MergingUpdateQueue.java +++ b/platform/platform-api/src/com/intellij/util/ui/update/MergingUpdateQueue.java @@ -123,8 +123,7 @@ public class MergingUpdateQueue implements Runnable, Disposable, Activatable { try { each.setRejected(); } - catch (ProcessCanceledException e) { - continue; + catch (ProcessCanceledException ignored) { } } myScheduledUpdates.clear(); @@ -237,7 +236,7 @@ public class MergingUpdateQueue implements Runnable, Disposable, Activatable { } }; - if (myExecuteInDispatchThread && invokeLaterIfNotDispatch && !ApplicationManager.getApplication().isDispatchThread()) { + if (myExecuteInDispatchThread && invokeLaterIfNotDispatch) { UIUtil.invokeLaterIfNeeded(toRun); } else { @@ -394,7 +393,7 @@ public class MergingUpdateQueue implements Runnable, Disposable, Activatable { public boolean isEmpty() { synchronized (myScheduledUpdates) { - return myScheduledUpdates.size() == 0; + return myScheduledUpdates.isEmpty(); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java b/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java new file mode 100644 index 000000000000..d2733c0af190 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/ClipboardSynchronizer.java @@ -0,0 +1,195 @@ +/* + * Copyright 2000-2011 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; + +import com.intellij.Patches; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.diagnostic.Logger; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * This class is used to workaround the problem with getting clipboard contents (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4818143). + * Although this bug is marked as fixed actually Sun just set 10 seconds timeout for {@link java.awt.datatransfer.Clipboard#getContents(Object)} + * method. So we perform synchronization with system clipboard on a separate thread and schedule it when IDEA frame is activated or Copy/Cut + * action in Swing component is invoked + * + * @author nik + */ +public class ClipboardSynchronizer implements ApplicationComponent { + private static final Logger LOG = Logger.getInstance("#com.intellij.ide.ClipboardSynchronizer"); + @NonNls private static final String DATA_TRANSFER_TIMEOUT_PROPERTY = "sun.awt.datatransfer.timeout"; + private AtomicBoolean mySynchronizationInProgress = new AtomicBoolean(false); + private Transferable myCurrentContent; + private final Object myLock = new Object(); + + public static ClipboardSynchronizer getInstance() { + return ApplicationManager.getApplication().getComponent(ClipboardSynchronizer.class); + } + + @Override + public void initComponent() { + if (!Patches.SLOW_GETTING_CLIPBOARD_CONTENTS) return; + + if (System.getProperty(DATA_TRANSFER_TIMEOUT_PROPERTY) == null) { + System.setProperty(DATA_TRANSFER_TIMEOUT_PROPERTY, "2000"); + } + + FrameStateManager.getInstance().addListener(new FrameStateListener() { + @Override + public void onFrameDeactivated() { + } + + @Override + public void onFrameActivated() { + scheduleSynchronization(); + } + }); + } + + public void replaceDefaultCopyPasteActions(UIDefaults defaults) { + if (!Patches.SLOW_GETTING_CLIPBOARD_CONTENTS) return; + + //ensure that '.actionMap' properties are initialized + new JTextField(); + new JPasswordField(); + new JTextArea(); + //noinspection UndesirableClassUsage + new JTable(); + + String[] textComponents = {"TextField", "PasswordField", "TextArea", "Table"}; + for (String name : textComponents) { + final String key = name + ".actionMap"; + final ActionMap actionMap = (ActionMap)defaults.get(key); + if (actionMap != null) { + replaceAction(actionMap, TransferHandler.getCopyAction()); + replaceAction(actionMap, TransferHandler.getCutAction()); + } + else { + LOG.warn(key + " property not initialized"); + } + } + } + + private void replaceAction(ActionMap actionMap, final Action action) { + final String actionName = (String)action.getValue(Action.NAME); + actionMap.put(actionName, new AbstractAction(actionName) { + @Override + public void actionPerformed(ActionEvent e) { + action.actionPerformed(e); + scheduleSynchronization(); + } + }); + } + + public Transferable getContents() { + if (Patches.SLOW_GETTING_CLIPBOARD_CONTENTS) { + synchronized (myLock) { + return myCurrentContent; + } + } + return doGetContents(); + } + + public boolean isDataFlavorAvailable(DataFlavor dataFlavor) { + if (Patches.SLOW_GETTING_CLIPBOARD_CONTENTS) { + final Transferable contents = getContents(); + return contents != null && contents.isDataFlavorSupported(dataFlavor); + } + return Toolkit.getDefaultToolkit().getSystemClipboard().isDataFlavorAvailable(dataFlavor); + } + + private void scheduleSynchronization() { + final boolean inProgress = mySynchronizationInProgress.getAndSet(true); + if (inProgress) return; + + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + try { + final Transferable content = doGetContents(); + synchronized (myLock) { + myCurrentContent = content; + } + } + catch (Throwable e) { + LOG.info(e); + } + finally { + mySynchronizationInProgress.set(false); + } + } + }); + } + + @Override + public void disposeComponent() { + } + + private Transferable doGetContents() { + IllegalStateException last = null; + for (int i = 0; i < 3; i++) { + try { + return Toolkit.getDefaultToolkit().getSystemClipboard().getContents(this); + } + catch (IllegalStateException e) { + try { + //noinspection BusyWait + Thread.sleep(50); + } + catch (InterruptedException ignored) { + } + last = e; + } + } + throw last; + } + + @NotNull + @Override + public String getComponentName() { + return "ClipboardSynchronizer"; + } + + public void setContent(Transferable content, ClipboardOwner owner) { + synchronized (myLock) { + myCurrentContent = content; + } + for (int i = 0; i < 3; i++) { + try { + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(content, owner); + } + catch (IllegalStateException e) { + try { + Thread.sleep(50); + } + catch (InterruptedException ignored) { + } + continue; + } + break; + } + } +} diff --git a/platform/platform-impl/src/com/intellij/ide/CopyPasteManagerEx.java b/platform/platform-impl/src/com/intellij/ide/CopyPasteManagerEx.java index b4506630d269..3c5d422ce0fd 100644 --- a/platform/platform-impl/src/com/intellij/ide/CopyPasteManagerEx.java +++ b/platform/platform-impl/src/com/intellij/ide/CopyPasteManagerEx.java @@ -15,132 +15,36 @@ */ package com.intellij.ide; -import com.intellij.Patches; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ApplicationNamesInfo; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.ide.CutElementMarker; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; import com.intellij.util.EventDispatcher; -import java.awt.*; import java.awt.datatransfer.*; import java.io.IOException; import java.util.ArrayList; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; public class CopyPasteManagerEx extends CopyPasteManager implements ClipboardOwner { - private static final Logger LOG = Logger.getInstance("#com.intellij.ide.CopyPasteManagerEx"); - private final ArrayList myDatas; - -// private static long ourWastedMemory = 0; -// private static long ourLastPrintedMemory = 0; -// private static long ourLastPrintTime = 0; -// private static long ourInvokationCounter = 0; - private final EventDispatcher myDispatcher = EventDispatcher.create(ContentChangedListener.class); - private static final int DELAY_UNTIL_ABORT_CLIPBOARD_ACCESS = 2000; - private boolean myIsWarningShown = false; + private final ClipboardSynchronizer myClipboardSynchronizer; public static CopyPasteManagerEx getInstanceEx() { return (CopyPasteManagerEx)getInstance(); } - public CopyPasteManagerEx() { + public CopyPasteManagerEx(ClipboardSynchronizer clipboardSynchronizer) { + myClipboardSynchronizer = clipboardSynchronizer; myDatas = new ArrayList(); } public Transferable getSystemClipboardContents() { - return getSystemClipboardContents(true); + return myClipboardSynchronizer.getContents(); } - public Transferable getSystemClipboardContents(boolean showMessage) { - final Transferable[] contents = new Transferable[] {null}; - final boolean[] success = new boolean[] {false}; - Runnable accessor = new Runnable() { - public void run() { - try { - for (int i = 0; i < 3; i++) { - try { - contents[0] = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(CopyPasteManagerEx.this); - } - catch (IllegalStateException e) { - try { - Thread.sleep(50); - } - catch (InterruptedException e1) { - } - continue; - } - break; - } - - success[0] = true; - } - catch (Throwable e) { - LOG.info(e); - // No luck - } - finally { - Thread.interrupted(); // reset interrupted status - } - } - }; - - if (Patches.SUN_BUG_ID_4818143) { - final Future accessorFuture = ApplicationManager.getApplication().executeOnPooledThread(accessor); - - try { - accessorFuture.get(DELAY_UNTIL_ABORT_CLIPBOARD_ACCESS, TimeUnit.MILLISECONDS); - } - catch (InterruptedException e) { - // {no luck} - } - catch (TimeoutException e) { - // {no luck} - } - catch (ExecutionException e) { - LOG.error(e); - } - - if (success[0]) return contents[0]; - accessorFuture.cancel(true); - if (showMessage) { - showWorkaroundMessage(); - } else { - LOG.warn("Can't access to SystemClipboard"); - } - - return null; - } - else { - accessor.run(); - return contents[0]; - } - } - - private void showWorkaroundMessage() { - if (myIsWarningShown) return; - final String productName = ApplicationNamesInfo.getInstance().getProductName(); - Messages.showErrorDialog(IdeBundle.message("error.paste.bug.workaround", productName, productName), IdeBundle.message("title.system.error")); - myIsWarningShown = true; - } - -// private long getUsedMemory() { -// Runtime runtime = Runtime.getRuntime(); -// long usedMemory = runtime.totalMemory() - runtime.freeMemory(); -// return usedMemory; -// } -// public void lostOwnership(Clipboard clipboard, Transferable contents) { fireContentChanged(null); } @@ -170,6 +74,10 @@ public class CopyPasteManagerEx extends CopyPasteManager implements ClipboardOwn fireContentChanged(old); } + public boolean isDataFlavorAvailable(DataFlavor dataFlavor) { + return myClipboardSynchronizer.isDataFlavorAvailable(dataFlavor); + } + public boolean isCutElement(final Object element) { for(CutElementMarker marker: Extensions.getExtensions(CutElementMarker.EP_NAME)) { if (marker.isCutElement(element)) return true; @@ -178,48 +86,7 @@ public class CopyPasteManagerEx extends CopyPasteManager implements ClipboardOwn } void setSystemClipboardContent(final Transferable content) { - final boolean[] success = new boolean[]{false}; - final Runnable accessor = new Runnable() { - public void run() { - try { - for (int i = 0; i < 3; i++) { - try { - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(content, CopyPasteManagerEx.this); - } - catch (IllegalStateException e) { - try { - Thread.sleep(50); - } - catch (InterruptedException e1) { - } - continue; - } - break; - } - success[0] = true; - } - finally { - Thread.interrupted(); // reset interrupted status - } - } - }; - - if (Patches.SUN_BUG_ID_4818143) { - Future accessorFuture = ApplicationManager.getApplication().executeOnPooledThread(accessor); - - try { - accessorFuture.get(DELAY_UNTIL_ABORT_CLIPBOARD_ACCESS, TimeUnit.MILLISECONDS); - } - catch (Exception e) { /* no luck */ } - - if (!success[0]) { - showWorkaroundMessage(); - accessorFuture.cancel(true); - } - } - else { - accessor.run(); - } + myClipboardSynchronizer.setContent(content, this); } private void addNewContentToStack(Transferable content) { diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index e978cc84e260..f222cd4772cd 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -366,6 +366,12 @@ public class IdeEventQueue extends EventQueue { try { _dispatchEvent(e); + } catch (ProcessCanceledException pce) { + throw pce; + } catch (Throwable exc) { + if (!myToolkitBugsProcessor.process(exc)) { + LOG.error("Error during dispatching of " + e, exc); + } } finally { myIsInInputEvent = wasInputEvent; diff --git a/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java b/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java index c4091286e937..223f1a11a8ef 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java @@ -137,7 +137,8 @@ public class CreateLauncherScriptAction extends AnAction { String homePath = PathManager.getHomePath(); String productName = ApplicationNamesInfo.getInstance().getProductName().toLowerCase(); if (SystemInfo.isMac) { - launcherContents = launcherContents.replace("$RUN_PATH$", homePath + "/Contents/MacOS/" + productName); + // Just use "*.app" + launcherContents = launcherContents.replace("$RUN_PATH$", homePath); } else { launcherContents = launcherContents.replace("$RUN_PATH$", homePath + "/bin/" + productName + ".sh"); diff --git a/platform/platform-impl/src/com/intellij/ide/actions/SelectAllAction.java b/platform/platform-impl/src/com/intellij/ide/actions/SelectAllAction.java index c66184fdb8c3..8b2d47a7deb1 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/SelectAllAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/SelectAllAction.java @@ -19,24 +19,27 @@ import com.intellij.ide.IdeBundle; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorAction; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.editor.actions.TextComponentEditorAction; import com.intellij.openapi.project.DumbAware; -public class SelectAllAction extends AnAction implements DumbAware { +public class SelectAllAction extends TextComponentEditorAction implements DumbAware { public SelectAllAction() { + super(new Handler()); setEnabledInModalContext(true); } - public void actionPerformed(AnActionEvent e) { - final DataContext dataContext = e.getDataContext(); - final Editor editor = TextComponentEditorAction.getEditorFromContext(dataContext); - if (editor == null) return; - CommandProcessor processor = CommandProcessor.getInstance(); - processor.executeCommand(PlatformDataKeys.PROJECT.getData(dataContext), new Runnable() { - public void run() { - editor.getSelectionModel().setSelection(0, editor.getDocument().getTextLength()); - } - }, IdeBundle.message("command.select.all"), null); + private static class Handler extends EditorActionHandler { + @Override + public void execute(final Editor editor, DataContext dataContext) { + CommandProcessor processor = CommandProcessor.getInstance(); + processor.executeCommand(PlatformDataKeys.PROJECT.getData(dataContext), new Runnable() { + public void run() { + editor.getSelectionModel().setSelection(0, editor.getDocument().getTextLength()); + } + }, IdeBundle.message("command.select.all"), null); + } } public void update(AnActionEvent event){ diff --git a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java index 3be56bce173b..c51575c075a5 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java @@ -22,12 +22,10 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.markup.EffectType; import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.fileEditor.impl.EditorHistoryManager; import com.intellij.openapi.fileEditor.impl.EditorWindow; -import com.intellij.openapi.fileEditor.impl.EditorsSplitters; import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; @@ -35,6 +33,7 @@ import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Iconable; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vcs.FileStatusManager; import com.intellij.openapi.vfs.VirtualFile; @@ -50,7 +49,6 @@ import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.components.JBList; import com.intellij.util.ArrayUtil; import com.intellij.util.IconUtil; -import com.intellij.util.Icons; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; @@ -61,7 +59,6 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.event.*; -import java.awt.image.BufferedImage; import java.io.File; import java.util.*; import java.util.List; @@ -158,7 +155,6 @@ public class Switcher extends AnAction implements DumbAware { final JLabel pathLabel = new JLabel(" "); final JPanel descriptions; final Project project; - final Map files2editors; final Map twShortcuts; @SuppressWarnings({"ManualArrayToCollectionCopy"}) @@ -209,7 +205,7 @@ public class Switcher extends AnAction implements DumbAware { toolWindows = new JBList(twModel); toolWindows.setBorder(IdeBorderFactory.createEmptyBorder(5, 5, 5, 20)); toolWindows.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - toolWindows.setCellRenderer(new ToolWindowsRenderer(ids, map) { + toolWindows.setCellRenderer(new SwitcherToolWindowsListRenderer(ids, map) { @Override public Component getListCellRendererComponent(JList list, Object value, @@ -250,38 +246,29 @@ public class Switcher extends AnAction implements DumbAware { return new Dimension(5, max.height); } }; - separator.setBackground(Color.WHITE); + separator.setBackground(Color.WHITE); - final FileEditorManager editorManager = FileEditorManager.getInstance(project); - final FileEditor[] allEditors = editorManager.getAllEditors(); - files2editors = new HashMap(); - for (FileEditor editor : allEditors) { - files2editors.put(((FileEditorManagerImpl)editorManager).getFile(editor), editor); + final FileEditorManagerImpl editorManager = (FileEditorManagerImpl)FileEditorManager.getInstance(project); + final ArrayList filesData = new ArrayList(); + final ArrayList editors = new ArrayList(); + for (Pair pair : editorManager.getSelectionHistory()) { + editors.add(new FileInfo(pair.first, pair.second)); } - final ArrayList openFiles = new ArrayList(); - final ArrayList editorFiles = new ArrayList(); - for (EditorsSplitters splitters : ((FileEditorManagerImpl)editorManager).getAllSplitters()) { - editorFiles.addAll(Arrays.asList(splitters.getOpenFiles())); - } - if (editorFiles.size() < 2) { + if (editors.size() < 2) { final VirtualFile[] recentFiles = ArrayUtil.reverseArray(EditorHistoryManager.getInstance(project).getFiles()); - final int len = Math.min(toolWindows.getModel().getSize(), Math.max(editorFiles.size(), recentFiles.length)); + final int len = Math.min(toolWindows.getModel().getSize(), Math.max(editors.size(), recentFiles.length)); for (int i = 0; i < len; i++) { - openFiles.add(recentFiles[i]); + filesData.add(new FileInfo(recentFiles[i], null)); } } else { - try { - ContainerUtil.sort(editorFiles, new RecentFilesComparator(project)); - } catch (Exception e) {// IndexNotReadyException - } - for (int i = 0; i < Math.min(MAX_FILES, editorFiles.size()); i++) { - openFiles.add(editorFiles.get(i)); + for (int i = 0; i < Math.min(MAX_FILES, editors.size()); i++) { + filesData.add(editors.get(i)); } } final DefaultListModel filesModel = new DefaultListModel(); - for (VirtualFile openFile : openFiles) { - filesModel.addElement(openFile); + for (FileInfo editor : filesData) { + filesModel.addElement(editor); } files = new JBList(filesModel); @@ -346,7 +333,7 @@ public class Switcher extends AnAction implements DumbAware { private void updatePathLabel() { final Object[] values = files.getSelectedValues(); if (values != null && values.length == 1) { - final VirtualFile parent = ((VirtualFile)values[0]).getParent(); + final VirtualFile parent = ((FileInfo)values[0]).first.getParent(); if (parent != null) { pathLabel.setText(getTitle2Text(parent.getPresentableUrl())); } else { @@ -460,25 +447,28 @@ public class Switcher extends AnAction implements DumbAware { private void closeTabOrToolWindow() { final Object value = getSelectedList().getSelectedValue(); - if (value instanceof VirtualFile) { - final VirtualFile virtualFile = (VirtualFile)value; - final FileEditorManager editorManager = FileEditorManager.getInstance(project); - if (editorManager instanceof FileEditorManagerImpl) { - final JList jList = getSelectedList(); - ((FileEditorManagerImpl)editorManager).closeFile(virtualFile, false); - final int selectedIndex = jList.getSelectedIndex(); - if (jList.getModel().getSize() == 1) { - goLeft(); - ((DefaultListModel)jList.getModel()).removeElementAt(selectedIndex); - this.remove(jList); - this.remove(separator); - } else { - goForward(); - ((DefaultListModel)jList.getModel()).removeElementAt(selectedIndex); - jList.setSize(jList.getPreferredSize()); - } - pack(); + if (value instanceof FileInfo) { + final FileInfo info = (FileInfo)value; + final VirtualFile virtualFile = info.first; + final FileEditorManagerImpl editorManager = ((FileEditorManagerImpl)FileEditorManager.getInstance(project)); + final JList jList = getSelectedList(); + if (info.second == null) { + editorManager.closeFile(virtualFile, false); + } else { + editorManager.closeFile(virtualFile, info.second, false); } + final int selectedIndex = jList.getSelectedIndex(); + if (jList.getModel().getSize() == 1) { + goLeft(); + ((DefaultListModel)jList.getModel()).removeElementAt(selectedIndex); + this.remove(jList); + this.remove(separator); + } else { + goForward(); + ((DefaultListModel)jList.getModel()).removeElementAt(selectedIndex); + jList.setSize(jList.getPreferredSize()); + } + pack(); } else if (value instanceof ToolWindow) { final ToolWindow toolWindow = (ToolWindow)value; if (twManager instanceof ToolWindowManagerImpl) { @@ -587,29 +577,23 @@ public class Switcher extends AnAction implements DumbAware { if (value instanceof ToolWindow) { ((ToolWindow)value).activate(null, true, true); } - else if (value instanceof VirtualFile) { - final VirtualFile file = (VirtualFile)value; + else if (value instanceof FileInfo) { + final FileInfo info = (FileInfo)value; IdeFocusManager.getInstance(project).doWhenFocusSettlesDown(new Runnable() { @Override public void run() { - FileEditorManager.getInstance(project).openFile(file, true, true); + final FileEditorManagerImpl manager = (FileEditorManagerImpl)FileEditorManager.getInstance(project); + if (info.second != null) { + manager.openFileImpl2(info.second, info.first, true); + manager.addSelectionRecord(info.first, info.second); + } else { + manager.openFile(info.first, true); + } } }); } } - private class RecentFilesComparator implements Comparator { - private final VirtualFile[] recentFiles; - - public RecentFilesComparator(Project project) { - recentFiles = EditorHistoryManager.getInstance(project).getFiles(); - } - - public int compare(VirtualFile vf1, VirtualFile vf2) { - return ArrayUtil.find(recentFiles, vf2) - ArrayUtil.find(recentFiles, vf1); - } - } - public void mouseClicked(MouseEvent e) { final Object source = e.getSource(); if (source instanceof JList) { @@ -673,8 +657,8 @@ public class Switcher extends AnAction implements DumbAware { } protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { - if (value instanceof VirtualFile) { - final VirtualFile virtualFile = (VirtualFile)value; + if (value instanceof FileInfo) { + final VirtualFile virtualFile = ((FileInfo)value).first; final String name = virtualFile.getPresentableName(); setIcon(IconUtil.getIcon(virtualFile, Iconable.ICON_FLAG_READ_STATUS, myProject)); @@ -685,64 +669,9 @@ public class Switcher extends AnAction implements DumbAware { } } - private static class ToolWindowsRenderer extends ColoredListCellRenderer { - private static final Map iconCache = new HashMap(); - private static final SimpleTextAttributes ID_STYLE = new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, Color.black); - private final Map ids; - private final Map shortcuts; - - public ToolWindowsRenderer(Map ids, Map shortcuts) { - this.ids = ids; - this.shortcuts = shortcuts; - } - - protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { - if (value instanceof ToolWindow) { - final ToolWindow tw = (ToolWindow)value; - setIcon(getIcon(tw)); - append(shortcuts.get(tw), ID_STYLE); - final String name = ": " + ids.get(tw); - - final TextAttributes attributes = new TextAttributes(Color.BLACK, null, null, EffectType.LINE_UNDERSCORE, Font.PLAIN); - append(name, SimpleTextAttributes.fromTextAttributes(attributes)); - } - } - - private Icon getIcon(ToolWindow toolWindow) { - Icon icon = iconCache.get(ids.get(toolWindow)); - if (icon != null) return icon; - - icon = toolWindow.getIcon(); - if (icon == null) { - return Icons.UI_FORM_ICON; - } - - icon = to16x16(icon); - iconCache.put(ids.get(toolWindow), icon); - return icon; - } - - private static Icon to16x16(Icon icon) { - if (icon.getIconHeight() == 16 && icon.getIconWidth() == 16) return icon; - final int w = Math.min (icon.getIconWidth(), 16); - final int h = Math.min(icon.getIconHeight(), 16); - - final BufferedImage image = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration() - .createCompatibleImage(16, 16, Color.TRANSLUCENT); - final Graphics2D g = image.createGraphics(); - icon.paintIcon(null, g, 0, 0); - g.dispose(); - - final BufferedImage img = new BufferedImage(16, 16, BufferedImage.TRANSLUCENT); - final int offX = Math.max((16 - w) / 2, 0); - final int offY = Math.max((16 - h) / 2, 0); - for (int col = 0; col < w; col++) { - for (int row = 0; row < h; row++) { - img.setRGB(col + offX, row + offY, image.getRGB(col, row)); - } - } - - return new ImageIcon(img); + private static class FileInfo extends Pair { + public FileInfo(VirtualFile first, EditorWindow second) { + super(first, second); } } } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java b/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java new file mode 100644 index 000000000000..594287d3af16 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/actions/SwitcherToolWindowsListRenderer.java @@ -0,0 +1,93 @@ +/* + * Copyright 2000-2011 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.actions; + +import com.intellij.openapi.editor.markup.EffectType; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.ui.ColoredListCellRenderer; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.util.Icons; + +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.Map; + +/** +* @author Konstantin Bulenkov +*/ +class SwitcherToolWindowsListRenderer extends ColoredListCellRenderer { + private static final Map iconCache = new HashMap(); + private static final SimpleTextAttributes ID_STYLE = new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, Color.black); + private final Map ids; + private final Map shortcuts; + + SwitcherToolWindowsListRenderer(Map ids, Map shortcuts) { + this.ids = ids; + this.shortcuts = shortcuts; + } + + protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { + if (value instanceof ToolWindow) { + final ToolWindow tw = (ToolWindow)value; + setIcon(getIcon(tw)); + append(shortcuts.get(tw), ID_STYLE); + final String name = ": " + ids.get(tw); + + final TextAttributes attributes = new TextAttributes(Color.BLACK, null, null, EffectType.LINE_UNDERSCORE, Font.PLAIN); + append(name, SimpleTextAttributes.fromTextAttributes(attributes)); + } + } + + private Icon getIcon(ToolWindow toolWindow) { + Icon icon = iconCache.get(ids.get(toolWindow)); + if (icon != null) return icon; + + icon = toolWindow.getIcon(); + if (icon == null) { + return Icons.UI_FORM_ICON; + } + + icon = to16x16(icon); + iconCache.put(ids.get(toolWindow), icon); + return icon; + } + + private static Icon to16x16(Icon icon) { + if (icon.getIconHeight() == 16 && icon.getIconWidth() == 16) return icon; + final int w = Math.min (icon.getIconWidth(), 16); + final int h = Math.min(icon.getIconHeight(), 16); + + final BufferedImage image = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration() + .createCompatibleImage(16, 16, Color.TRANSLUCENT); + final Graphics2D g = image.createGraphics(); + icon.paintIcon(null, g, 0, 0); + g.dispose(); + + final BufferedImage img = new BufferedImage(16, 16, BufferedImage.TRANSLUCENT); + final int offX = Math.max((16 - w) / 2, 0); + final int offY = Math.max((16 - h) / 2, 0); + for (int col = 0; col < w; col++) { + for (int row = 0; row < h; row++) { + img.setRGB(col + offX, row + offY, image.getRGB(col, row)); + } + } + + return new ImageIcon(img); + } +} diff --git a/platform/platform-impl/src/com/intellij/ide/errorTreeView/ErrorViewStructure.java b/platform/platform-impl/src/com/intellij/ide/errorTreeView/ErrorViewStructure.java index 6336e78cd75e..3a2021a2071a 100644 --- a/platform/platform-impl/src/com/intellij/ide/errorTreeView/ErrorViewStructure.java +++ b/platform/platform-impl/src/com/intellij/ide/errorTreeView/ErrorViewStructure.java @@ -28,6 +28,7 @@ import com.intellij.ui.SimpleColoredComponent; import com.intellij.util.ArrayUtil; import com.intellij.util.ui.MutableErrorTreeView; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.*; @@ -142,20 +143,31 @@ public class ErrorViewStructure extends AbstractTreeStructure { return false; } - public void addMessage(ErrorTreeElementKind kind, String[] text, VirtualFile file, int line, int column, Object data) { - if (file != null) { + public void addMessage(ErrorTreeElementKind kind, + @NotNull String[] text, + @Nullable VirtualFile underFileGroup, + @Nullable VirtualFile file, + int line, + int column, + @Nullable Object data) { + if (underFileGroup != null || file != null) { + if (file == null) line = column = -1; + final int guiline = line < 0 ? -1 : line + 1; - final int guicolumn = column < 0 ? -1:column + 1; + final int guicolumn = column < 0 ? -1 : column + 1; + + VirtualFile group = underFileGroup != null ? underFileGroup : file; + VirtualFile nav = file != null ? file : underFileGroup; addNavigatableMessage( - file.getPresentableUrl(), - new OpenFileDescriptor(myProject, file, line, column), + group.getPresentableUrl(), + new OpenFileDescriptor(myProject, nav, line, column), kind, text, data, NewErrorTreeViewPanel.createExportPrefix(guiline), NewErrorTreeViewPanel.createRendererPrefix(guiline, guicolumn), - file + group ); } else { diff --git a/platform/platform-impl/src/com/intellij/ide/errorTreeView/NewErrorTreeViewPanel.java b/platform/platform-impl/src/com/intellij/ide/errorTreeView/NewErrorTreeViewPanel.java index e5f3eb16d4da..d91271637dde 100644 --- a/platform/platform-impl/src/com/intellij/ide/errorTreeView/NewErrorTreeViewPanel.java +++ b/platform/platform-impl/src/com/intellij/ide/errorTreeView/NewErrorTreeViewPanel.java @@ -38,6 +38,7 @@ import com.intellij.util.ui.MutableErrorTreeView; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; @@ -230,6 +231,7 @@ public class NewErrorTreeViewPanel extends JPanel implements DataProvider, Occur protected boolean shouldShowFirstErrorInEditor() { return false; } + public void clearMessages() { myErrorViewStructure.clear(); myBuilder.updateTree(); @@ -238,14 +240,36 @@ public class NewErrorTreeViewPanel extends JPanel implements DataProvider, Occur public void updateTree() { myBuilder.updateTree(); } - public void addMessage(int type, String[] text, VirtualFile file, int line, int column, Object data) { - myErrorViewStructure.addMessage(ErrorTreeElementKind.convertMessageFromCompilerErrorType(type), text, file, line, column, data); + + public void addMessage(int type, @NotNull String[] text, @Nullable VirtualFile file, int line, int column, @Nullable Object data) { + addMessage(type, text, null, file, line, column, data); + } + + @Override + public void addMessage(int type, + @NotNull String[] text, + @Nullable VirtualFile underFileGroup, + @Nullable VirtualFile file, + int line, + int column, + @Nullable Object data) { + myErrorViewStructure + .addMessage(ErrorTreeElementKind.convertMessageFromCompilerErrorType(type), text, underFileGroup, file, line, column, data); myBuilder.updateTree(); } - public void addMessage(int type, String[] text, String groupName, Navigatable navigatable, String exportTextPrefix, String rendererTextPrefix, Object data) { - myErrorViewStructure.addNavigatableMessage(groupName, navigatable, ErrorTreeElementKind.convertMessageFromCompilerErrorType(type), text, data, exportTextPrefix, rendererTextPrefix, - data instanceof VirtualFile ? (VirtualFile) data : null); + public void addMessage(int type, + @NotNull String[] text, + @NotNull String groupName, + @NotNull Navigatable navigatable, + @Nullable String exportTextPrefix, + @Nullable String rendererTextPrefix, + @Nullable Object data) { + myErrorViewStructure.addNavigatableMessage(groupName, navigatable, ErrorTreeElementKind.convertMessageFromCompilerErrorType(type), text, + data, + exportTextPrefix == null ? "" : exportTextPrefix, + rendererTextPrefix == null ? "" : rendererTextPrefix, + data instanceof VirtualFile ? (VirtualFile)data : null); myBuilder.updateTree(); } @@ -254,11 +278,13 @@ public class NewErrorTreeViewPanel extends JPanel implements DataProvider, Occur } public static String createExportPrefix(int line) { - return line < 0? "" : IdeBundle.message("errortree.prefix.line", line); + return line < 0 ? "" : IdeBundle.message("errortree.prefix.line", line); } public static String createRendererPrefix(int line, int column) { - return line < 0? "" : "(" + line + ", " + column + ")"; + if (line < 0) return ""; + if (column < 0) return "(" + line + ")"; + return "(" + line + ", " + column + ")"; } public JComponent getComponent() { @@ -267,7 +293,7 @@ public class NewErrorTreeViewPanel extends JPanel implements DataProvider, Occur private NavigatableMessageElement getSelectedMessageElement() { final ErrorTreeElement selectedElement = getSelectedErrorTreeElement(); - return selectedElement instanceof NavigatableMessageElement? (NavigatableMessageElement)selectedElement : null; + return selectedElement instanceof NavigatableMessageElement ? (NavigatableMessageElement)selectedElement : null; } public ErrorTreeElement getSelectedErrorTreeElement() { @@ -423,7 +449,7 @@ public class NewErrorTreeViewPanel extends JPanel implements DataProvider, Occur if (rerunAction != null) { leftUpdateableActionGroup.add(new RerunAction(rerunAction, closeMessageViewAction)); } - + leftUpdateableActionGroup.add(new StopAction()); if (myCreateExitAction) { leftUpdateableActionGroup.add(closeMessageViewAction); @@ -439,10 +465,10 @@ public class NewErrorTreeViewPanel extends JPanel implements DataProvider, Occur JPanel toolbarPanel = new JPanel(new GridLayout(1, 2)); final ActionManager actionManager = ActionManager.getInstance(); myLeftToolbar = - actionManager.createActionToolbar(ActionPlaces.COMPILER_MESSAGES_TOOLBAR, leftUpdateableActionGroup, false); + actionManager.createActionToolbar(ActionPlaces.COMPILER_MESSAGES_TOOLBAR, leftUpdateableActionGroup, false); toolbarPanel.add(myLeftToolbar.getComponent()); myRightToolbar = - actionManager.createActionToolbar(ActionPlaces.COMPILER_MESSAGES_TOOLBAR, rightUpdateableActionGroup, false); + actionManager.createActionToolbar(ActionPlaces.COMPILER_MESSAGES_TOOLBAR, rightUpdateableActionGroup, false); toolbarPanel.add(myRightToolbar.getComponent()); return toolbarPanel; @@ -521,7 +547,7 @@ public class NewErrorTreeViewPanel extends JPanel implements DataProvider, Occur } } - protected boolean canHideWarnings(){ + protected boolean canHideWarnings() { return true; } @@ -543,11 +569,11 @@ public class NewErrorTreeViewPanel extends JPanel implements DataProvider, Occur } } } - + public boolean isHideWarnings() { return ErrorTreeViewConfiguration.getInstance(myProject).isHideWarnings(); } - + private class MyTreeExpander implements TreeExpander { public void expandAll() { NewErrorTreeViewPanel.this.expandAll(); diff --git a/platform/platform-impl/src/com/intellij/ide/ui/LafManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/LafManagerImpl.java index 0f759e40252a..d1140782b60f 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/LafManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/LafManagerImpl.java @@ -16,6 +16,7 @@ package com.intellij.ide.ui; import com.intellij.CommonBundle; +import com.intellij.ide.ClipboardSynchronizer; import com.intellij.ide.IdeBundle; import com.intellij.idea.StartupUtil; import com.intellij.notification.Notification; @@ -489,6 +490,7 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo public void updateUI() { UIDefaults lookAndFeelDefaults=UIManager.getLookAndFeelDefaults(); initInputMapDefaults(lookAndFeelDefaults); + initActionMapDefaults(lookAndFeelDefaults); patchFileChooserStrings(lookAndFeelDefaults); if (shouldPatchLAFFonts()) { storeOriginalFontDefaults(lookAndFeelDefaults); @@ -630,6 +632,10 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo } } + private static void initActionMapDefaults(UIDefaults defaults) { + ClipboardSynchronizer.getInstance().replaceDefaultCopyPasteActions(defaults); + } + @SuppressWarnings({"HardCodedStringLiteral"}) private void initFontDefaults(UIDefaults defaults) { defaults.put("Tree.ancestorInputMap", null); diff --git a/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesAction.java b/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesAction.java index e90aa6a7b251..07ceb7496142 100644 --- a/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesAction.java +++ b/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesAction.java @@ -25,6 +25,9 @@ import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.impl.FocusManagerImpl; import com.intellij.openapi.wm.impl.FocusRequestInfo; +import java.awt.*; +import java.awt.event.AWTEventListener; +import java.awt.event.FocusEvent; import java.util.ArrayList; import java.util.List; @@ -33,6 +36,7 @@ import java.util.List; */ public class FocusTracesAction extends AnAction implements DumbAware { private static boolean myActive = false; + private AWTEventListener myFocusTracker; public static boolean isActive() { return myActive; @@ -46,10 +50,23 @@ public class FocusTracesAction extends AnAction implements DumbAware { final FocusManagerImpl focusManager = (FocusManagerImpl)manager; myActive = !myActive; + if (myActive) { + myFocusTracker = new AWTEventListener() { + @Override + public void eventDispatched(AWTEvent event) { + if (event instanceof FocusEvent && event.getID() == FocusEvent.FOCUS_GAINED) { + focusManager.getRequests().add(new FocusRequestInfo(((FocusEvent)event).getComponent(), new Throwable(), false)); + } + } + }; + Toolkit.getDefaultToolkit().addAWTEventListener(myFocusTracker, AWTEvent.FOCUS_EVENT_MASK); + } if (!myActive) { final List requests = focusManager.getRequests(); new FocusTracesDialog(project, new ArrayList(requests)).show(); + Toolkit.getDefaultToolkit().removeAWTEventListener(myFocusTracker); + myFocusTracker = null; requests.clear(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java index f1b74c760c8b..208cfbff866e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java @@ -84,7 +84,7 @@ public class StorageUtil { @NotNull HyperlinkEvent event) { ((ProjectEx)project).checkUnknownMacros(true); } - }, macros), NotificationDisplayType.STICKY_BALLOON, project); + }, macros), project); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineEndAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineEndAction.java index 154423330c7c..96a96401710e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineEndAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineEndAction.java @@ -25,17 +25,13 @@ package com.intellij.openapi.editor.actions; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler; import com.intellij.openapi.ide.CopyPasteManager; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.ui.EmptyClipboardOwner; -import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; public class CutLineEndAction extends EditorAction { @@ -63,7 +59,7 @@ public class CutLineEndAction extends EditorAction { } if (myCopyToClipboard) { - copyToClipboard(doc, caretOffset, lineEndOffset, dataContext, editor); + copyToClipboard(doc, caretOffset, lineEndOffset); } final int lineStartOffset = doc.getLineStartOffset(lineNumber); @@ -75,24 +71,12 @@ public class CutLineEndAction extends EditorAction { } } - private static void copyToClipboard(final Document doc, - int caretOffset, - int lineEndOffset, - DataContext dataContext, - Editor editor) { + private static void copyToClipboard(final Document doc, int caretOffset, int lineEndOffset) { String s = doc.getCharsSequence().subSequence(caretOffset, lineEndOffset).toString(); s = StringUtil.convertLineSeparators(s); StringSelection contents = new StringSelection(s); - - Project project = PlatformDataKeys.PROJECT.getData(dataContext); - if (project == null) { - Clipboard clipboard = editor.getComponent().getToolkit().getSystemClipboard(); - clipboard.setContents(contents, EmptyClipboardOwner.INSTANCE); - } - else { - CopyPasteManager.getInstance().setContents(contents); - } + CopyPasteManager.getInstance().setContents(contents); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToBottomAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToBottomAction.java new file mode 100644 index 000000000000..b971dce1cf45 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToBottomAction.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.actions; + +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; +import com.intellij.openapi.editor.ex.EditorEx; + +/** + * Scrolls to the top of the target editor without changing its caret position. + * + * @author Denis Zhdanov + * @since 2/22/11 11:17 AM + */ +public class ScrollToBottomAction extends InactiveEditorAction { + + public ScrollToBottomAction() { + super(new MyHandler()); + } + + private static class MyHandler extends EditorActionHandler { + @Override + public void execute(Editor editor, DataContext dataContext) { + if (editor == null) { + return; + } + editor.getScrollingModel().scrollTo(editor.offsetToLogicalPosition(editor.getDocument().getTextLength()), ScrollType.CENTER); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToTopAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToTopAction.java new file mode 100644 index 000000000000..a3771a173725 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToTopAction.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.actions; + +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; + +/** + * Scrolls to the top of the target editor without changing its caret position. + * + * @author Denis Zhdanov + * @since 2/22/11 11:17 AM + */ +public class ScrollToTopAction extends InactiveEditorAction { + + public ScrollToTopAction() { + super(new MyHandler()); + } + + private static class MyHandler extends EditorActionHandler { + @Override + public void execute(Editor editor, DataContext dataContext) { + if (editor == null) { + return; + } + editor.getScrollingModel().scrollVertically(0); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java index c8a218c3a956..91d6c9fb3ab1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java @@ -365,7 +365,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, EditorSettings editorSettings = myEditor.getSettings(); - if (!editorSettings.isVirtualSpace() && line < lineCount) { + if (!editorSettings.isVirtualSpace() && line < lineCount && !myEditor.getSelectionModel().hasBlockSelection()) { int lineEndOffset = doc.getLineEndOffset(line); int lineEndColumnNumber = myEditor.offsetToLogicalPosition(lineEndOffset).column; if (column > lineEndColumnNumber) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index e003cb69d206..699c7ff1eb09 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -55,6 +55,7 @@ import com.intellij.openapi.editor.impl.softwrap.SoftWrapHelper; import com.intellij.openapi.editor.markup.*; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory; +import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.options.FontSize; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; @@ -76,7 +77,6 @@ import com.intellij.util.containers.HashMap; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.text.CharArrayUtil; import com.intellij.util.ui.ButtonlessScrollBarUI; -import com.intellij.util.ui.EmptyClipboardOwner; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.update.UiNotifyConnector; import gnu.trove.TIntArrayList; @@ -95,7 +95,6 @@ import javax.swing.border.EmptyBorder; import javax.swing.plaf.ScrollBarUI; import javax.swing.plaf.basic.BasicScrollBarUI; import java.awt.*; -import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; @@ -765,6 +764,9 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi int oldFontSize = myScheme.getEditorFontSize(); myScheme.setEditorFontSize(fontSize); myPropertyChangeSupport.firePropertyChange(PROP_FONT_SIZE, oldFontSize, fontSize); + // Update vertical scroll bar bounds if necessary (we had a problem that use increased editor font size and it was not possible + // to scroll to the bottom of the document). + myScrollPane.getViewport().invalidate(); } public ActionCallback type(final String text) { @@ -3255,7 +3257,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi return; } - if (!mySettings.isVirtualSpace()) { + if (!mySettings.isVirtualSpace() && !mySelectionModel.hasBlockSelection()) { int lineEndOffset = myDocument.getLineEndOffset(lineNumber); int lineEndColumnNumber = calcColumnNumber(lineEndOffset, lineNumber); if (columnNumber > lineEndColumnNumber) { @@ -5161,12 +5163,12 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi if (editor.getDocument().getRangeGuard(offset, offset) != null) return; EditorActionHandler pasteHandler = EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_PASTE); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + final CopyPasteManager copyPasteManager = CopyPasteManager.getInstance(); Transferable backup = null; try { - backup = clipboard.getContents(this); - clipboard.setContents(t, EmptyClipboardOwner.INSTANCE); + backup = copyPasteManager.getContents(); + copyPasteManager.setContents(t); } catch (Exception e) { LOG.info("Error communicating with system clipboard", e); @@ -5176,7 +5178,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi pasteHandler.execute(editor, editor.getDataContext()); try { if (backup != null) { - clipboard.setContents(backup, EmptyClipboardOwner.INSTANCE); + copyPasteManager.setContents(backup); } } catch (IllegalStateException e) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java index ecce8d321218..04812916c5e3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java @@ -24,6 +24,7 @@ */ package com.intellij.openapi.editor.impl; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.ex.MarkupModelEx; @@ -54,11 +55,13 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx private final RangeHighlighterTree myHighlighterTree; MarkupModelImpl(DocumentImpl document) { + ApplicationManager.getApplication().assertIsDispatchThread(); myDocument = document; myHighlighterTree = new RangeHighlighterTree(myDocument); } public void dispose() { + ApplicationManager.getApplication().assertIsDispatchThread(); myHighlighterTree.dispose(); } @@ -98,9 +101,11 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx @NotNull public RangeHighlighter[] getAllHighlighters() { + ApplicationManager.getApplication().assertIsDispatchThread(); if (myCachedHighlighters == null) { - if (myHighlighterTree.size() == 0) return RangeHighlighter.EMPTY_ARRAY; - List list = new ArrayList(); + int size = myHighlighterTree.size(); + if (size == 0) return RangeHighlighter.EMPTY_ARRAY; + List list = new ArrayList(size); myHighlighterTree.process(new CommonProcessors.CollectProcessor(list)); myCachedHighlighters = list.toArray(new RangeHighlighter[list.size()]); } @@ -115,6 +120,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx @NotNull HighlighterTargetArea targetArea, boolean isPersistent, @Nullable Consumer changeAttributesAction) { + ApplicationManager.getApplication().assertIsDispatchThread(); RangeHighlighterEx highlighter = isPersistent ? new PersistentRangeHighlighterImpl(this, startOffset, layer, targetArea, textAttributes) : new RangeHighlighterImpl(this, startOffset, endOffset, layer, targetArea, textAttributes); @@ -134,6 +140,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx @Override public void changeAttributesInBatch(@NotNull RangeHighlighterEx highlighter, @NotNull Consumer changeAttributesAction) { + ApplicationManager.getApplication().assertIsDispatchThread(); boolean changed = highlighter instanceof PersistentRangeHighlighterImpl ? ((PersistentRangeHighlighterImpl)highlighter).changeAttributesInBatch(changeAttributesAction) : ((RangeHighlighterImpl)highlighter).changeAttributesInBatch(changeAttributesAction); @@ -143,6 +150,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx } void addRangeHighlighter(RangeHighlighterEx marker, int start, int end, RangeHighlighterData data) { + ApplicationManager.getApplication().assertIsDispatchThread(); myHighlighterTree.addInterval(marker, start, end, data); } @@ -156,6 +164,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx } public void removeHighlighter(@NotNull RangeHighlighter segmentHighlighter) { + ApplicationManager.getApplication().assertIsDispatchThread(); myCachedHighlighters = null; if (!segmentHighlighter.isValid()) return; @@ -166,6 +175,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx } public void removeAllHighlighters() { + ApplicationManager.getApplication().assertIsDispatchThread(); myHighlighterTree.process(new Processor() { public boolean process(RangeMarkerEx rangeMarkerEx) { fireBeforeRemoved((RangeHighlighterEx)rangeMarkerEx); @@ -191,6 +201,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx } public void setRangeHighlighterAttributes(@NotNull final RangeHighlighter highlighter, final TextAttributes textAttributes) { + ApplicationManager.getApplication().assertIsDispatchThread(); ((RangeHighlighterImpl)highlighter).setTextAttributes(textAttributes); } @@ -211,6 +222,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx } public boolean containsHighlighter(@NotNull final RangeHighlighter highlighter) { + ApplicationManager.getApplication().assertIsDispatchThread(); return !myHighlighterTree.processOverlappingWith(highlighter.getStartOffset(), highlighter.getEndOffset(), new Processor() { public boolean process(RangeHighlighterEx h) { return h.getId() != ((RangeHighlighterEx)highlighter).getId(); @@ -236,6 +248,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx } public void normalize() { + ApplicationManager.getApplication().assertIsDispatchThread(); myHighlighterTree.normalize(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java index c69e6b5468e5..1a5c6c8f5178 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java @@ -24,9 +24,7 @@ */ package com.intellij.openapi.editor.impl; -import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; @@ -44,7 +42,6 @@ import com.intellij.openapi.editor.ex.PrioritizedDocumentListener; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.ide.CopyPasteManager; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; @@ -255,7 +252,7 @@ public class SelectionModelImpl implements SelectionModel, PrioritizedDocumentLi // removeSelection(); //} - return marker != null && marker.isValid(); + return marker != null && marker.isValid() && marker.getEndOffset() > marker.getStartOffset(); } public void setSelection(int startOffset, int endOffset) { @@ -728,15 +725,7 @@ public class SelectionModelImpl implements SelectionModel, PrioritizedDocumentLi s = StringUtil.convertLineSeparators(s); StringSelection contents = new StringSelection(s); - - Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(myEditor.getContentComponent())); - if (project == null) { - Clipboard clipboard = myEditor.getComponent().getToolkit().getSystemClipboard(); - clipboard.setContents(contents, EmptyClipboardOwner.INSTANCE); - } - else { - CopyPasteManager.getInstance().setContents(contents); - } + CopyPasteManager.getInstance().setContents(contents); } public TextAttributes getTextAttributes() { diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java index 93302fc94716..8e01d4613be5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java @@ -35,6 +35,7 @@ import com.intellij.ui.PrevNextActionsDescriptor; import com.intellij.ui.SideBorder; import com.intellij.ui.TabbedPaneWrapper; import com.intellij.ui.tabs.UiDecorator; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -236,6 +237,11 @@ public abstract class EditorComposite implements Disposable { publisher.selectionChanged(event); } }); + final JComponent component = newSelectedEditor.getComponent(); + final EditorWindowHolder holder = UIUtil.getParentOfType(EditorWindowHolder.class, component); + if (holder != null) { + ((FileEditorManagerImpl)myFileEditorManager).addSelectionRecord(myFile, holder.getEditorWindow()); + } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java index 138b9ef0fb91..31856ce03327 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java @@ -138,7 +138,7 @@ public class EditorWindow { beforePublisher.beforeFileClosed(editorManager, file); - if (myTabbedPane != null) { + if (myTabbedPane != null && editor != null) { final int componentIndex = findComponentIndex(editor.getComponent()); if (componentIndex >= 0) { // editor could close itself on decomposition final int indexToSelect = calcIndexToSelect(file, componentIndex); @@ -167,6 +167,7 @@ public class EditorWindow { } } finally { + editorManager.getSelectionHistory().remove(new Pair(file, EditorWindow.this)); final FileEditorManagerListener afterPublisher = editorManager.getProject().getMessageBus().syncPublisher(FileEditorManagerListener.FILE_EDITOR_MANAGER); @@ -325,15 +326,22 @@ public class EditorWindow { return myTabbedPane; } - protected static class TComp extends JPanel implements DataProvider{ + protected static class TComp extends JPanel implements DataProvider, EditorWindowHolder { final EditorWithProviderComposite myEditor; + protected final EditorWindow myWindow; - TComp(final EditorWithProviderComposite editor) { + TComp(final EditorWindow window, final EditorWithProviderComposite editor) { super(new BorderLayout()); myEditor = editor; + myWindow = window; add(editor.getComponent(), BorderLayout.CENTER); } + @Override + public EditorWindow getEditorWindow() { + return myWindow; + } + public Object getData(String dataId) { if (PlatformDataKeys.VIRTUAL_FILE.is(dataId)){ final VirtualFile virtualFile = myEditor.getFile(); @@ -347,11 +355,8 @@ public class EditorWindow { } protected static class TCompForTablessMode extends TComp{ - private final EditorWindow myWindow; - TCompForTablessMode(final EditorWindow window, final EditorWithProviderComposite editor) { - super(editor); - myWindow = window; + super(window, editor); } public Object getData(String dataId) { @@ -434,7 +439,7 @@ public class EditorWindow { final int indexToInsert = initialIndex == null ? myTabbedPane.getSelectedIndex() + 1 : initialIndex; final VirtualFile file = editor.getFile(); final Icon template = IconLoader.getIcon("/fileTypes/text.png"); - myTabbedPane.insertTab(file, new EmptyIcon(template.getIconWidth(), template.getIconHeight()), new TComp(editor), null, indexToInsert); + myTabbedPane.insertTab(file, new EmptyIcon(template.getIconWidth(), template.getIconHeight()), new TComp(this, editor), null, indexToInsert); trimToSize(UISettings.getInstance().EDITOR_TAB_LIMIT, file, false); setSelectedEditor(editor, focusEditor); myOwner.updateFileIcon(file); diff --git a/java/openapi/src/com/intellij/psi/PsiAspectManagerListener.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindowHolder.java similarity index 74% rename from java/openapi/src/com/intellij/psi/PsiAspectManagerListener.java rename to platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindowHolder.java index d2a03d0be508..c708d058b63b 100644 --- a/java/openapi/src/com/intellij/psi/PsiAspectManagerListener.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindowHolder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2011 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,13 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.psi; +package com.intellij.openapi.fileEditor.impl; /** - * AspectJ functionality; currently not supported. - * - * @author max + * @author Konstantin Bulenkov */ -public interface PsiAspectManagerListener { - void update(); +public interface EditorWindowHolder { + EditorWindow getEditorWindow(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index 36b48a92bd06..b7926537679e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -60,9 +60,11 @@ import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.StatusBarEx; import com.intellij.ui.docking.DockContainer; import com.intellij.ui.docking.DockManager; +import com.intellij.ui.tabs.TabInfo; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.messages.impl.MessageListenerList; +import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; import org.jdom.Element; @@ -93,6 +95,9 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec private volatile JPanel myPanels; private EditorsSplitters mySplitters; private final Project myProject; + private final List myTabsHistory = new ArrayList(); + private final List> mySelectionHistory = new ArrayList>(); + private final MergingUpdateQueue myQueue = new MergingUpdateQueue("FileEditorManagerUpdateQueue", 50, true, null); @@ -140,8 +145,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec HashSet all = new HashSet(); all.add(getMainSplitters()); Set dockContainers = DockManager.getInstance(myProject).getContainers(); - for (Iterator iterator = dockContainers.iterator(); iterator.hasNext();) { - DockContainer each = iterator.next(); + for (DockContainer each : dockContainers) { if (each instanceof DockableEditorTabbedContainer) { all.add(((DockableEditorTabbedContainer)each).getSplitters()); } @@ -473,13 +477,13 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec getSplitters().setCurrentWindow(window, true); } - public void closeFile(@NotNull final VirtualFile file, @NotNull final EditorWindow window) { + public void closeFile(@NotNull final VirtualFile file, @NotNull final EditorWindow window, final boolean transferFocus) { assertDispatchThread(); CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { public void run() { if (window.isFileOpen(file)) { - window.closeFile(file); + window.closeFile(file, true, transferFocus); final List windows = window.getOwner().findWindows(file); if (windows.isEmpty()) { // no more windows containing this file left final LocalFileSystem.WatchRequest request = file.getUserData(WATCH_REQUEST_KEY); @@ -490,6 +494,11 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec } } }, IdeBundle.message("command.close.active.editor"), null); + removeSelectionRecord(file, window); + } + + public void closeFile(@NotNull final VirtualFile file, @NotNull final EditorWindow window) { + closeFile(file, window, true); } //============================= EditorManager methods ================================ @@ -1250,6 +1259,14 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec final FileEditorManagerEvent event = new FileEditorManagerEvent(this, oldSelectedFile, oldSelectedEditor, newSelectedFile, newSelectedEditor); final FileEditorManagerListener publisher = getProject().getMessageBus().syncPublisher(FileEditorManagerListener.FILE_EDITOR_MANAGER); + + if (newSelectedEditor != null) { + final JComponent component = newSelectedEditor.getComponent(); + final EditorWindowHolder holder = UIUtil.getParentOfType(EditorWindowHolder.class, component); + if (holder != null) { + addSelectionRecord(newSelectedFile, holder.getEditorWindow()); + } + } IdeFocusManager.getInstance(myProject).doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) { @Override public void run() { @@ -1600,4 +1617,23 @@ private final class MyVirtualFileListener extends VirtualFileAdapter { return splitters; } + public void selectionChanged(VirtualFile file, EditorWindow window) { + final Pair selection = new Pair(file, window); + mySelectionHistory.remove(selection); + mySelectionHistory.add(0, selection); + } + + public List> getSelectionHistory() { + return mySelectionHistory; + } + + public void addSelectionRecord(VirtualFile file, EditorWindow window) { + final Pair record = new Pair(file, window); + mySelectionHistory.remove(record); + mySelectionHistory.add(0, record); + } + + private void removeSelectionRecord(VirtualFile file, EditorWindow window) { + mySelectionHistory.remove(new Pair(file, window)); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java index 0bfe3de7e8e9..bdb2580b0964 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java @@ -98,6 +98,11 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME static { final FileTypeConsumer consumer = new FileTypeConsumer() { + @Override + public void consume(@NotNull FileType fileType) { + register(fileType, parse(fileType.getDefaultExtension())); + } + public void consume(@NotNull final FileType fileType, final String extensions) { register(fileType, parse(extensions)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java index 7779474e25c3..e08edf4ef380 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java @@ -71,7 +71,11 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { public boolean isVisible() { return false; } - + + @Override + public ActionCallback getReady(Object requestor) { + return new ActionCallback.Done(); + } public void show(@Nullable Runnable runnable) { } @@ -175,6 +179,12 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { }; @NonNls private static final ContentManager MOCK_CONTENT_MANAGER = new ContentManager() { + + @Override + public ActionCallback getReady(Object requestor) { + return new ActionCallback.Done(); + } + public void addContent(@NotNull final Content content) { } public void addContent(@NotNull Content content, int order) { } public void addContent(@NotNull final Content content, final Object constraints) { } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java index f84197091b98..a5ecf97f5c77 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java @@ -20,16 +20,18 @@ import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.util.ActionCallback; -import com.intellij.openapi.wm.ToolWindowAnchor; -import com.intellij.openapi.wm.ToolWindowContentUiType; -import com.intellij.openapi.wm.ToolWindowFactory; -import com.intellij.openapi.wm.ToolWindowType; +import com.intellij.openapi.util.BusyObject; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.wm.*; import com.intellij.openapi.wm.ex.ToolWindowEx; +import com.intellij.openapi.wm.impl.commands.FinalizableCommand; import com.intellij.openapi.wm.impl.content.ToolWindowContentUi; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentFactory; import com.intellij.ui.content.ContentManager; import com.intellij.ui.content.impl.ContentImpl; +import com.intellij.util.ui.update.Activatable; +import com.intellij.util.ui.update.UiNotifyConnector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,6 +40,7 @@ import java.awt.*; import java.awt.event.InputEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.util.ArrayList; /** * @author Anton Katilin @@ -62,6 +65,12 @@ public final class ToolWindowImpl implements ToolWindowEx { private ToolWindowFactory myContentFactory; private ActionCallback myActivation = new ActionCallback.Done(); + private BusyObject.Impl myShowing = new BusyObject.Impl() { + @Override + protected boolean isReady() { + return myComponent != null && myComponent.isShowing(); + } + }; ToolWindowImpl(final ToolWindowManagerImpl toolWindowManager, final String id, boolean canCloseContent, @Nullable final JComponent component) { myToolWindowManager = toolWindowManager; @@ -81,6 +90,14 @@ public final class ToolWindowImpl implements ToolWindowEx { } myComponent = myContentManager.getComponent(); + + UiNotifyConnector notifyConnector = new UiNotifyConnector(myComponent, new Activatable.Adapter() { + @Override + public void showNotify() { + myShowing.onReady(); + } + }); + Disposer.register(myContentManager, notifyConnector); } public final void addPropertyChangeListener(final PropertyChangeListener l) { @@ -117,6 +134,30 @@ public final class ToolWindowImpl implements ToolWindowEx { return myToolWindowManager.isToolWindowActive(myId) || (myDecorator != null && myDecorator.isFocused()); } + @Override + public ActionCallback getReady(final Object requestor) { + final ActionCallback result = new ActionCallback(); + myShowing.getReady(this).doWhenDone(new Runnable() { + @Override + public void run() { + ArrayList cmd = new ArrayList(); + cmd.add(new FinalizableCommand(null) { + @Override + public void run() { + IdeFocusManager.getInstance(myToolWindowManager.getProject()).doWhenFocusSettlesDown(new Runnable() { + @Override + public void run() { + myContentManager.getReady(requestor).notify(result); + } + }); + } + }); + myToolWindowManager.execute(cmd); + } + }); + return result; + } + public final void show(final Runnable runnable) { ApplicationManager.getApplication().assertIsDispatchThread(); myToolWindowManager.showToolWindow(myId); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index a8350a7cd5dd..f5afba27ec5b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -519,7 +519,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements * This is helper method. It delegated its fuctionality to the WindowManager. * Before delegating it fires state changed. */ - private void execute(final ArrayList commandList) { + public void execute(final ArrayList commandList) { for (FinalizableCommand each : commandList) { if (each.willChangeState()) { fireStateChanged(); diff --git a/platform/platform-impl/src/com/intellij/ui/content/impl/ContentImpl.java b/platform/platform-impl/src/com/intellij/ui/content/impl/ContentImpl.java index 4487d294804a..d345f257b02c 100644 --- a/platform/platform-impl/src/com/intellij/ui/content/impl/ContentImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/content/impl/ContentImpl.java @@ -18,10 +18,7 @@ package com.intellij.ui.content.impl; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.ActionGroup; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.IconLoader; -import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.openapi.util.*; import com.intellij.ui.LayeredIcon; import com.intellij.ui.content.AlertIcon; import com.intellij.ui.content.Content; @@ -57,6 +54,7 @@ public class ContentImpl extends UserDataHolderBase implements Content { private JComponent mySearchComponent; private Computable myFocusRequest; + private BusyObject myBusyObject; public ContentImpl(JComponent component, String displayName, boolean isPinnable) { myComponent = component; @@ -264,6 +262,16 @@ public class ContentImpl extends UserDataHolderBase implements Content { myChangeSupport.firePropertyChange(PROP_ALERT, null, true); } + @Override + public void setBusyObject(BusyObject object) { + myBusyObject = object; + } + + @Override + public BusyObject getBusyObject() { + return myBusyObject; + } + public void setSearchComponent(@Nullable final JComponent comp) { mySearchComponent = comp; } diff --git a/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java b/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java index 2e3707e37bb0..f47c0df6739f 100644 --- a/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java @@ -23,10 +23,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.ActionCallback; -import com.intellij.openapi.util.ActiveRunnable; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.*; import com.intellij.openapi.wm.FocusCommand; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy; @@ -109,6 +106,13 @@ public class ContentManagerImpl implements ContentManager, PropertyChangeListene return myComponent; } + @Override + public ActionCallback getReady(Object requestor) { + Content selected = getSelectedContent(); + BusyObject busyObject = selected.getBusyObject(); + return busyObject != null ? busyObject.getReady(requestor) : new ActionCallback.Done(); + } + private class MyContentComponent extends NonOpaquePanel implements DataProvider, SwitchProvider { private final List myProviders = new ArrayList(); diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 1f15ebcbf287..cb21d7434c35 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -87,6 +87,8 @@ action.EditorTab.text=Tab action.EmacsStyleIndent.text=Emacs Tab action.EditorScrollUp.text=Scroll Up action.EditorScrollDown.text=Scroll Down +action.EditorScrollTop.text=Scroll to Top +action.EditorScrollBottom.text=Scroll to Bottom action.EditorMoveUpAndScroll.text=Move Up and Scroll action.EditorMoveDownAndScroll.text=Move Down and Scroll action.EditorMoveUpAndScrollWithSelection.text=Move Up and Scroll with Selection diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index d6e18c427278..ffaf57f2093f 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -131,6 +131,7 @@ wrapping.and.braces=Wrapping and Braces wrapping.keep.when.reformatting=Keep when reformatting wrapping.keep.line.breaks=Line breaks wrapping.keep.comment.at.first.column=Comment at first column +wrapping.keep.simple.classes.in.one.line=Simple classes in one line wrapping.keep.simple.methods.in.one.line=Simple methods in one line wrapping.keep.multiple.expressions.in.one.line=Multiple expressions in one line wrapping.keep.simple.blocks.in.one.line=Simple blocks in one line diff --git a/platform/platform-resources-en/src/messages/ExecutionBundle.properties b/platform/platform-resources-en/src/messages/ExecutionBundle.properties index 66abc2caa26d..325b17dd811f 100644 --- a/platform/platform-resources-en/src/messages/ExecutionBundle.properties +++ b/platform/platform-resources-en/src/messages/ExecutionBundle.properties @@ -222,7 +222,7 @@ no.applet.class.specified.error.message=No applet class specified no.main.class.specified.error.text=No main class specified action.name.save.configuration=Save Configuration #2 - configuration type description -empty.run.configuration.panel.text.label=

Press the \\  button \ +empty.run.configuration.panel.text.label=

Press the \\  button \ to create a new {3} based on default settings. default.package.presentable.name= default.package.configuration.name=default package diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 7ded1a7c5fc4..61305fb25489 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -10,7 +10,6 @@ button.finish=&Finish button.ok=&OK button.wizard.previous=< &Previous button.wizard.next=&Next > -error.paste.bug.workaround=You''re seeing this message because of the workaround to JRE issue: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4818143\n{0} would hang otherwise. The system clipboard might be not working correctly. It is recommended to restart {1}. title.system.error=System Error title.select.path.to.browser=Select Path to Browser title.general=General diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index b13535f0b77c..84ff14dabe0a 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -504,7 +504,10 @@ + + + @@ -610,4 +613,5 @@ + diff --git a/platform/platform-resources/src/componentSets/Platform.xml b/platform/platform-resources/src/componentSets/Platform.xml index fa0f63758036..9605bc3a9c51 100644 --- a/platform/platform-resources/src/componentSets/Platform.xml +++ b/platform/platform-resources/src/componentSets/Platform.xml @@ -123,6 +123,11 @@ com.intellij.internal.statistic.persistence.ApplicationStatisticsPersistenceComponent + + com.intellij.ide.ClipboardSynchronizer + com.intellij.ide.ClipboardSynchronizer + + com.intellij.openapi.util.FoundationLoader diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index f448f143b688..22b63fd3e470 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -50,6 +50,8 @@ + + diff --git a/platform/platform-resources/src/launcher.py b/platform/platform-resources/src/launcher.py index 0bcc36326934..79183be49cef 100644 --- a/platform/platform-resources/src/launcher.py +++ b/platform/platform-resources/src/launcher.py @@ -69,6 +69,13 @@ if port == -1: else: if launch_with_port(port): exit() -bin_dir, bin_file = os.path.split(RUN_PATH) -os.chdir(bin_dir) -os.execv(bin_file, [bin_file] + args) +if sys.platform == "darwin": + # Mac OS: RUN_PATH is *.app path + if len(args): + args.insert(0, "--args") + os.execvp("open", ["-a", RUN_PATH] + args) +else: + # unix common + bin_dir, bin_file = os.path.split(RUN_PATH) + os.chdir(bin_dir) + os.execv(bin_file, [bin_file] + args) diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestComparisionFailedState.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestComparisionFailedState.java index 79cf7e93881c..eb49e38fe8b6 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestComparisionFailedState.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestComparisionFailedState.java @@ -74,7 +74,7 @@ public class TestComparisionFailedState extends TestFailedState implements Abstr } @Override - public String getExpecteed() { + public String getExpected() { return myHyperlink.getLeft(); } diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java index ee6627924f92..e455ec2534fe 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java @@ -15,7 +15,8 @@ */ package com.intellij.testFramework; -import com.intellij.ide.*; +import com.intellij.ide.DataManager; +import com.intellij.ide.IdeEventQueue; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.ide.util.treeView.AbstractTreeStructure; import com.intellij.idea.Bombed; @@ -48,9 +49,10 @@ import org.jetbrains.annotations.TestOnly; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; -import java.util.*; import java.awt.*; import java.awt.event.InvocationEvent; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; /** @@ -99,14 +101,14 @@ public class PlatformTestUtil { } public static String print(JTree tree, boolean withSelection, Condition nodePrintCondition) { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); Object root = tree.getModel().getRoot(); printImpl(tree, root, buffer, 0, withSelection, nodePrintCondition); return buffer.toString(); } - private static void printImpl(JTree tree, Object root, StringBuffer buffer, int level, boolean withSelection, @Nullable Condition nodePrintCondition) { + private static void printImpl(JTree tree, Object root, StringBuilder buffer, int level, boolean withSelection, @Nullable Condition nodePrintCondition) { DefaultMutableTreeNode defaultMutableTreeNode = (DefaultMutableTreeNode)root; @@ -116,7 +118,7 @@ public class PlatformTestUtil { nodeText = toString(userObject, null); } else { - nodeText = defaultMutableTreeNode + ""; + nodeText = String.valueOf(defaultMutableTreeNode); } @@ -163,8 +165,10 @@ public class PlatformTestUtil { Assert.assertEquals(expected, treeStringPresentation); } + @TestOnly public static void waitForAlarm(final int delay) throws InterruptedException { - final boolean[] invoked = new boolean[]{false}; + assert !ApplicationManager.getApplication().isWriteAccessAllowed(): "It's a bad idea to wait for an alarm under the write action. Somebody creates an alarm which requires read action and you are deadlocked."; + final AtomicBoolean invoked = new AtomicBoolean(); final Alarm alarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); alarm.addRequest(new Runnable() { @Override @@ -175,7 +179,7 @@ public class PlatformTestUtil { alarm.addRequest(new Runnable() { @Override public void run() { - invoked[0] = true; + invoked.set(true); } }, delay); } @@ -185,10 +189,13 @@ public class PlatformTestUtil { UIUtil.dispatchAllInvocationEvents(); - while (!invoked[0]) { + boolean sleptAlready = false; + while (!invoked.get()) { UIUtil.dispatchAllInvocationEvents(); - Thread.sleep(delay); + Thread.sleep(sleptAlready ? 10 : delay); + sleptAlready = true; } + UIUtil.dispatchAllInvocationEvents(); } @TestOnly diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 8f4e0f96b186..aad0fdc8cd78 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.diagnostic.PerformanceWatcher; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; @@ -696,4 +697,8 @@ public abstract class UsefulTestCase extends TestCase { } return false; } + + protected String getHomePath() { + return PathManager.getHomePath().replace(File.separatorChar, '/'); + } } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 89efb3a06d46..fda1738327c7 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -741,6 +741,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig protected void run() throws Exception { configureByFiles(ArrayUtil.reverseArray(ArrayUtil.append(additionalFiles, filePath))); final VirtualFile file = findFileInTempDir(to); + assert file != null : "Directory " + to + " not found"; assert file.isDirectory() : to + " is not a directory"; final PsiDirectory directory = myPsiManager.findDirectory(file); new MoveFilesOrDirectoriesProcessor(project, new PsiElement[]{myFile}, directory, diff --git a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java index 3ddc3f1d9821..433f7fda572c 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java @@ -131,7 +131,7 @@ public abstract class AbstractTestProxy extends CompositePrintable { public interface AssertEqualsDiffViewerProvider { void openDiff(final Project project); - String getExpecteed(); + String getExpected(); String getActual(); } } diff --git a/platform/usageView/src/com/intellij/usages/impl/GroupNode.java b/platform/usageView/src/com/intellij/usages/impl/GroupNode.java index 583fce9f8caa..991a365e5f9c 100644 --- a/platform/usageView/src/com/intellij/usages/impl/GroupNode.java +++ b/platform/usageView/src/com/intellij/usages/impl/GroupNode.java @@ -105,7 +105,10 @@ public class GroupNode extends Node implements Navigatable, Comparable implements Disposable { if (timed == null) continue; synchronized (timed) { if (timed.myLastCheckedAccessCount == timed.myAccessCount && !timed.isLocked()) { - Disposer.dispose(timed); + timed.dispose(); } else { timed.myLastCheckedAccessCount = timed.myAccessCount; diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 3aee063622d7..c388ba725271 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -372,6 +372,15 @@ public class ContainerUtil { } } + public static Map stringMap(@NotNull final String... keyValues) { + final Map result = new HashMap(); + for (int i = 0; i < keyValues.length - 1; i+=2) { + result.put(keyValues[i], keyValues[i+1]); + } + + return result; + } + @NotNull public static Iterator iterate(@NotNull T[] arrays) { return Arrays.asList(arrays).iterator(); diff --git a/platform/util/src/com/intellij/util/containers/LongArrayList.java b/platform/util/src/com/intellij/util/containers/LongArrayList.java index 9a6ae1a07541..c0c9bb42ff87 100644 --- a/platform/util/src/com/intellij/util/containers/LongArrayList.java +++ b/platform/util/src/com/intellij/util/containers/LongArrayList.java @@ -15,6 +15,7 @@ */ package com.intellij.util.containers; +@Deprecated // use TLongArrayList instead public class LongArrayList implements Cloneable { private long[] myData; private int mySize; diff --git a/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java b/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java index 4f374caaa6c0..abe2edbb296e 100644 --- a/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java +++ b/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java @@ -52,7 +52,7 @@ public class TransferToEDTQueue { T thing = myQueue.poll(); if (thing == null) break; if (!myProcessor.process(thing)) { - myQueue.clear(); + stop(); return; } processed++; diff --git a/platform/util/src/com/intellij/util/containers/WeakList.java b/platform/util/src/com/intellij/util/containers/WeakList.java index 0691a02d68b2..3bb72781c520 100644 --- a/platform/util/src/com/intellij/util/containers/WeakList.java +++ b/platform/util/src/com/intellij/util/containers/WeakList.java @@ -76,6 +76,13 @@ public class WeakList extends AbstractList { } } + @Override + public boolean removeAll(Collection c) { + synchronized (myArray) { + return super.removeAll(c); + } + } + public Iterator iterator() { return new MyIterator(); } @@ -88,7 +95,7 @@ public class WeakList extends AbstractList { public List toStrongList() { synchronized (myArray) { - List result = new ArrayList(); + List result = new ArrayList(myArray.size()); myArray.toStrongCollection(result); return result; } diff --git a/platform/util/src/com/intellij/util/ui/FormBuilder.java b/platform/util/src/com/intellij/util/ui/FormBuilder.java index 780d0d05633f..9e17a2a96b67 100644 --- a/platform/util/src/com/intellij/util/ui/FormBuilder.java +++ b/platform/util/src/com/intellij/util/ui/FormBuilder.java @@ -25,25 +25,34 @@ import java.awt.*; public class FormBuilder { private int line = 0; + private int indent; private final JPanel panel; private boolean vertical; /** * @param vertical labels will be placed on their own rows */ - public FormBuilder(final boolean vertical) { + public FormBuilder(final boolean vertical, final int indent) { this.vertical = vertical; panel = new JPanel(new GridBagLayout()); + this.indent = indent; + } + + public FormBuilder(final boolean vertical) { + this(vertical, 5); } public FormBuilder() { - this(false); + this(false, 5); } public FormBuilder addLabeledComponent(String labelText, JComponent component) { - JLabel label = new JLabel(UIUtil.removeMnemonic(labelText)); - label.setDisplayedMnemonicIndex(UIUtil.getDisplayMnemonicIndex(labelText)); - label.setLabelFor(component); + JLabel label = null; + if (labelText != null) { + label = new JLabel(UIUtil.removeMnemonic(labelText)); + label.setDisplayedMnemonicIndex(UIUtil.getDisplayMnemonicIndex(labelText)); + label.setLabelFor(component); + } GridBagConstraints c = new GridBagConstraints(); int verticalInset = line > 0 ? 10 : 0; @@ -56,16 +65,16 @@ public class FormBuilder { c.weightx = 1.0; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; - c.insets = new Insets(verticalInset, 0, 0, 5); + c.insets = new Insets(verticalInset, 0, 0, this.indent); - panel.add(label, c); + if (label != null) panel.add(label, c); c.gridx = 0; c.gridy = line + 1; c.weightx = 1.0; - c.fill = GridBagConstraints.HORIZONTAL; + c.fill = component instanceof JComboBox ? GridBagConstraints.NONE : GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; - c.insets = new Insets(0, 0, 0, 5); + c.insets = new Insets(0, 0, 0, this.indent); panel.add(component, c); @@ -76,13 +85,13 @@ public class FormBuilder { c.gridy = line; c.weightx = 0; c.anchor = GridBagConstraints.EAST; - c.insets = new Insets(verticalInset, 0, 0, 5); + c.insets = new Insets(verticalInset, 0, 0, this.indent); - panel.add(label, c); + if (label != null) panel.add(label, c); c.gridx = 1; c.gridy = line; - c.fill = GridBagConstraints.HORIZONTAL; + c.fill = component instanceof JComboBox ? GridBagConstraints.NONE : GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; c.weightx = 1; c.insets = new Insets(verticalInset, 0, 0, 0); diff --git a/platform/util/src/com/intellij/util/ui/GridBag.java b/platform/util/src/com/intellij/util/ui/GridBag.java new file mode 100644 index 000000000000..95fd4ea59cba --- /dev/null +++ b/platform/util/src/com/intellij/util/ui/GridBag.java @@ -0,0 +1,418 @@ +/* + * Copyright 2000-2011 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.util.ui; + +import gnu.trove.TIntDoubleHashMap; +import gnu.trove.TIntIntHashMap; +import gnu.trove.TIntObjectHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; + +/** + * Usage: + *

+ * {@code
+ *
+ * // First, configure default for every or a specific column:
+ * GridBag bag = new GridBag()
+ *     .setDefaultAnchor(0, GridBagConstraints.EAST)
+ *     .setDefaultAnchor(1, GridBagConstraints.WEST)
+ *     .setDefaultWeightX(1, 1)
+ *     .setDefaultFill(GridBagConstraints.HORIZONTAL);
+ *
+ * // Then, add components to a panel:
+ *
+ * // The following code adds a new line with 2 components with default settings:
+ * panel.add(c1, bag.nextLine().next())
+ * panel.add(c1, bag.next())
+ *
+ * // The following code adds a component on the next line that covers all remaining columns:
+ * panel.add(c1, bag.nextLine().coverLine())
+ *
+ * // The following code adds a component on the next line with overridden settings:
+ * panel.add(c1, bag.nextLine().next().insets(...).weightx(...))
+ *
+ * // You also can pre-configure the object and pass it as a constraint:
+ * bag.nextLine().next();
+ * panel.add(c1, bag)
+ * }
+ * 
+ * Note that every call of {@link #nextLine()} or {@link #next()} resets settings to the defaults for the corresponding column. + */ +@SuppressWarnings({"JavaDoc"}) +public class GridBag extends GridBagConstraints { + private int myDefaultAnchor = anchor; + @NotNull private final TIntIntHashMap myDefaultColumnAnchors = new TIntIntHashMap(); + + private int myDefaultFill = fill; + @NotNull private final TIntIntHashMap myDefaultColumnFills = new TIntIntHashMap(); + + private double myDefaultWeightX = weightx; + @NotNull private final TIntDoubleHashMap myDefaultColumnWeightsX = new TIntDoubleHashMap(); + private double myDefaultWeightY = weighty; + @NotNull private final TIntDoubleHashMap myDefaultColumnWeightsY = new TIntDoubleHashMap(); + + private int myDefaultPaddingX = ipadx; + @NotNull private final TIntIntHashMap myDefaultColumnPaddingsX = new TIntIntHashMap(); + private int myDefaultPaddingY = ipady; + @NotNull private final TIntIntHashMap myDefaultColumnPaddingsY = new TIntIntHashMap(); + + @Nullable private Insets myDefaultInsets = insets; + @NotNull private final TIntObjectHashMap myDefaultColumnInsets = new TIntObjectHashMap(); + + public GridBag() { + gridx = gridy = -1; + } + + @NotNull + public GridBag nextLine() { + gridy++; + gridx = -1; + return reset(); + } + + @NotNull + public GridBag next() { + gridx++; + return reset(); + } + + public int getLine() { + return gridy; + } + + @NotNull + public GridBag setLine(int line) { + gridy = line; + return this; + } + + public int getColumn() { + return gridx; + } + + @NotNull + public GridBag setColumn(int cell) { + gridx = cell; + return this; + } + + @NotNull + public GridBag reset() { + gridwidth = gridheight = 1; + + int column = gridx; + + anchor(getDefaultAnchor(column)); + fill = getDefaultFill(column); + weightx(getDefaultWeightX(column)); + weighty(getDefaultWeightY(column)); + padx(getDefaultPaddingX(column)); + pady(getDefaultPaddingY(column)); + insets(getDefaultInsets(column)); + return this; + } + + @NotNull + public GridBag anchor(int anchor) { + this.anchor = anchor; + return this; + } + + @NotNull + public GridBag fillCell() { + fill = GridBagConstraints.BOTH; + return this; + } + + @NotNull + public GridBag fillCellHorizontally() { + fill = GridBagConstraints.HORIZONTAL; + return this; + } + + @NotNull + public GridBag fillCellVertically() { + fill = GridBagConstraints.VERTICAL; + return this; + } + + @NotNull + public GridBag weightx(double weight) { + weightx = weight; + return this; + } + + + @NotNull + public GridBag weighty(double weight) { + weighty = weight; + return this; + } + + @NotNull + public GridBag coverLine() { + gridwidth = GridBagConstraints.REMAINDER; + return this; + } + + @NotNull + public GridBag coverLine(int cells) { + gridwidth = cells; + return this; + } + + @NotNull + public GridBag coverColumn() { + gridheight = GridBagConstraints.REMAINDER; + return this; + } + + @NotNull + public GridBag coverColumn(int cells) { + gridheight = cells; + return this; + } + + @NotNull + public GridBag padx(int padding) { + ipadx = padding; + return this; + } + + @NotNull + public GridBag pady(int padding) { + ipady = padding; + return this; + } + + + /** + * @see #insets(java.awt.Insets) + */ + @NotNull + public GridBag insets(int top, int left, int bottom, int right) { + return insets(new Insets(top, left, bottom, right)); + } + + /** + * Pass -1 to use a default value for this column. + * E.g, Insets(10, -1, -1, -1) means that 'top' will be changed to 10 and other sides will be set to defaults for this column. + */ + @NotNull + public GridBag insets(@Nullable Insets insets) { + if (insets != null && (insets.top < 0 || insets.bottom < 0 || insets.left < 0 || insets.right < 0)) { + Insets def = getDefaultInsets(gridx); + insets = (Insets)insets.clone(); + if (insets.top < 0) insets.top = def == null ? 0 : def.top; + if (insets.left < 0) insets.left = def == null ? 0 : def.left; + if (insets.bottom < 0) insets.bottom = def == null ? 0 : def.bottom; + if (insets.right < 0) insets.right = def == null ? 0 : def.right; + } + this.insets = insets; + return this; + } + + public int getDefaultAnchor() { + return myDefaultAnchor; + } + + @NotNull + public GridBag setDefaultAnchor(int anchor) { + myDefaultAnchor = anchor; + return this; + } + + public int getDefaultAnchor(int column) { + return myDefaultColumnAnchors.containsKey(column) ? myDefaultColumnAnchors.get(column) : getDefaultAnchor(); + } + + @NotNull + public GridBag setDefaultAnchor(int column, int anchor) { + if (anchor == -1) { + myDefaultColumnAnchors.remove(column); + } + else { + myDefaultColumnAnchors.put(column, anchor); + } + return this; + } + + public int getDefaultFill() { + return myDefaultFill; + } + + @NotNull + public GridBag setDefaultFill(int fill) { + myDefaultFill = fill; + return this; + } + + public int getDefaultFill(int column) { + return myDefaultColumnFills.containsKey(column) ? myDefaultColumnFills.get(column) : getDefaultFill(); + } + + @NotNull + public GridBag setDefaultFill(int column, int fill) { + if (fill == -1) { + myDefaultColumnFills.remove(column); + } + else { + myDefaultColumnFills.put(column, fill); + } + return this; + } + + public double getDefaultWeightX() { + return myDefaultWeightX; + } + + @NotNull + public GridBag setDefaultWeightX(double weight) { + myDefaultWeightX = weight; + return this; + } + + public double getDefaultWeightX(int column) { + return myDefaultColumnWeightsX.containsKey(column) ? myDefaultColumnWeightsX.get(column) : getDefaultWeightX(); + } + + @NotNull + public GridBag setDefaultWeightX(int column, double weight) { + if (weight == -1) { + myDefaultColumnWeightsX.remove(column); + } + else { + myDefaultColumnWeightsX.put(column, weight); + } + return this; + } + + + public double getDefaultWeightY() { + return myDefaultWeightY; + } + + @NotNull + public GridBag setDefaultWeightY(double weight) { + myDefaultWeightY = weight; + return this; + } + + public double getDefaultWeightY(int column) { + return myDefaultColumnWeightsY.containsKey(column) ? myDefaultColumnWeightsY.get(column) : getDefaultWeightY(); + } + + @NotNull + public GridBag setDefaultWeightY(int column, double weight) { + if (weight == -1) { + myDefaultColumnWeightsY.remove(column); + } + else { + myDefaultColumnWeightsY.put(column, weight); + } + return this; + } + + + public int getDefaultPaddingX() { + return myDefaultPaddingX; + } + + @NotNull + public GridBag setDefaultPaddingX(int padding) { + myDefaultPaddingX = padding; + return this; + } + + public int getDefaultPaddingX(int column) { + return myDefaultColumnPaddingsX.containsKey(column) ? myDefaultColumnPaddingsX.get(column) : getDefaultPaddingX(); + } + + @NotNull + public GridBag setDefaultPaddingX(int column, int padding) { + if (padding == -1) { + myDefaultColumnPaddingsX.remove(column); + } + else { + myDefaultColumnPaddingsX.put(column, padding); + } + return this; + } + + public int getDefaultPaddingY() { + return myDefaultPaddingY; + } + + @NotNull + public GridBag setDefaultPaddingY(int padding) { + myDefaultPaddingY = padding; + return this; + } + + public int getDefaultPaddingY(int column) { + return myDefaultColumnPaddingsY.containsKey(column) ? myDefaultColumnPaddingsY.get(column) : getDefaultPaddingY(); + } + + @NotNull + public GridBag setDefaultPaddingY(int column, int padding) { + if (padding == -1) { + myDefaultColumnPaddingsY.remove(column); + } + else { + myDefaultColumnPaddingsY.put(column, padding); + } + return this; + } + + @Nullable + public Insets getDefaultInsets() { + return myDefaultInsets; + } + + @NotNull + public GridBag setDefaultInsets(int top, int left, int bottom, int right) { + return setDefaultInsets(new Insets(top, left, bottom, right)); + } + + public GridBag setDefaultInsets(@Nullable Insets insets) { + myDefaultInsets = insets; + return this; + } + + @Nullable + public Insets getDefaultInsets(int column) { + return myDefaultColumnInsets.containsKey(column) ? myDefaultColumnInsets.get(column) : getDefaultInsets(); + } + + @NotNull + public GridBag setDefaultInsets(int column, int top, int left, int bottom, int right) { + return setDefaultInsets(column, new Insets(top, left, bottom, right)); + } + + @NotNull + public GridBag setDefaultInsets(int column, @Nullable Insets insets) { + if (insets == null) { + myDefaultColumnInsets.remove(column); + } + else { + myDefaultColumnInsets.put(column, insets); + } + return this; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 8cad05468417..19b949b8de96 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -387,15 +387,15 @@ anonymous.class.parameter.hides.containing.method.variable.problem.descriptor=An anonymous.class.field.hides.containing.method.variable.problem.descriptor=Anonymous class field #ref hides variable in containing method #loc anonymous.class.variable.hides.containing.method.variable.problem.descriptor=Anonymous class local variable #ref hides variable in containing method #loc channel.opened.not.closed.display.name=Channel opened but not safely closed -channel.opened.not.closed.problem.descriptor=''{0}'' should be opened in front of a try block and closed in the corresponding finally block #loc +channel.opened.not.closed.problem.descriptor=''{0}'' should be opened in front of a ''try'' block and closed in the corresponding ''finally'' block #loc drivermanager.call.display.name=Use of DriverManager to get JDBC connection drivermanager.call.problem.descriptor=Call to DriverManager.#ref() #loc hibernate.resource.opened.not.closed.display.name=Hibernate resource opened but not safely closed -hibernate.resource.opened.not.closed.problem.descriptor=''{0}'' should be opened in front of a try block and closed in the corresponding finally block #loc +hibernate.resource.opened.not.closed.problem.descriptor=''{0}'' should be opened in front of a ''try'' block and closed in the corresponding ''finally'' block #loc i.o.resource.opened.not.closed.display.name=I/O resource opened but not safely closed -resource.opened.not.closed.problem.descriptor=''{0}'' should be opened in front of a try block and closed in the corresponding finally block #loc +resource.opened.not.closed.problem.descriptor=''{0}'' should be opened in front of a ''try'' block and closed in the corresponding ''finally'' block #loc jdbc.resource.opened.not.closed.display.name=JDBC resource opened but not safely closed -jdbc.resource.opened.not.closed.problem.descriptor=JDBC ''{0}'' should be opened in front of a try block and closed in the corresponding finally block #loc +jdbc.resource.opened.not.closed.problem.descriptor=JDBC ''{0}'' should be opened in front of a ''try'' block and closed in the corresponding ''finally'' block #loc jndi.resource.opened.not.closed.display.name=JNDI resource opened but not safely closed socket.opened.not.closed.display.name=Socket opened but not safely closed annotation.class.display.name=Annotation class @@ -674,7 +674,7 @@ c.style.array.declaration.display.name=C-style array declaration final.method.in.final.class.display.name='final' method in 'final' class extends.annotation.display.name=Class extends annotation interface naked.notify.display.name='notify()' or 'notifyAll()' without corresponding state change -constant.if.statement.display.name=Constant if statement +constant.if.statement.display.name=Constant 'if' statement switch.statement.density.display.name='switch' statement with too low of a branch density switch.statement.with.too.few.branches.display.name='switch' statement with too few branches upper.case.field.name.not.constant.display.name=Non-constant field with upper-case name @@ -691,7 +691,7 @@ system.set.security.manager.problem.descriptor=Call to System.#ref()#ref() can b floating.point.equality.problem.descriptor=#ref: floating point values compared for exact equality #loc fallthru.in.switch.statement.problem.descriptor=#ref fallthrough in 'switch' statement #loc switch.statements.without.default.problem.descriptor=#ref statement without 'default' branch #loc -default.not.last.case.in.switch.problem.descriptor=#ref branch not last case in 'switch' #loc +default.not.last.case.in.switch.problem.descriptor=#ref branch not last case in 'switch' statement #loc loop.statements.that.dont.loop.problem.descriptor=#ref statement does not loop #loc conditional.expression.with.identical.branches.problem.descriptor=Conditional expression #ref with identical branches #loc if.statement.with.identical.branches.problem.descriptor=#ref statement with identical branches #loc @@ -890,7 +890,7 @@ implicit.call.to.super.problem.descriptor=Implicit call to super() #ref#ref statement with negated condition #loc negated.conditional.problem.descriptor=Conditional expression with negated condition #loc confusing.else.problem.descriptor=#ref branch may be unwrapped, as the if branch never completes #loc -switch.statement.with.confusing.declaration.problem.descriptor=Local variable #ref declared in one switch branch and used in another #loc +switch.statement.with.confusing.declaration.problem.descriptor=Local variable #ref declared in one 'switch' branch and used in another #loc raw.use.of.parameterized.type.problem.descriptor=Raw use of parameterized class #ref #loc final.class.problem.descriptor=Class declared #ref #loc empty.class.problem.descriptor=Class #ref is empty #loc @@ -932,10 +932,10 @@ interface.never.implemented.problem.descriptor=Interface #ref has n missing.deprecated.annotation.problem.descriptor=Missing '@Deprecated' annotation on #ref() #loc missing.override.annotation.problem.descriptor=Missing '@Override' annotation on #ref() #loc non.thread.safe.lazy.initialization.problem.descriptor=Lazy initialization of static field #ref is not thread-safe #loc -catch.generic.class.problem.descriptor=catch of generic #ref class should be replaced with more precise exception #loc +catch.generic.class.problem.descriptor='catch' of generic #ref class should be replaced with more precise exception #loc empty.catch.block.problem.descriptor=Empty #ref block #loc -unused.catch.parameter.problem.descriptor=Unused catch parameter #ref #loc -used.catch.parameter.named.ignore.problem.descriptor=Catch parameter named #ref is used #loc +unused.catch.parameter.problem.descriptor=Unused 'catch' parameter #ref #loc +used.catch.parameter.named.ignore.problem.descriptor='catch' parameter named #ref is used #loc empty.finally.block.problem.descriptor=Empty #ref block #loc finally.block.cannot.complete.normally.problem.descriptor=#ref block can not complete normally #loc empty.try.block.problem.descriptor=Empty #ref block #loc @@ -1142,7 +1142,7 @@ local.variable.naming.convention.problem.descriptor.short=Local variable name #ref is too long #loc local.variable.naming.convention.problem.descriptor.regex.mismatch=Local variable name #ref doesn''t match regex ''{0}'' #loc local.variable.naming.convention.ignore.option=Ignore for-loop parameters -local.variable.naming.convention.ignore.catch.option=Ignore catch block parameters +local.variable.naming.convention.ignore.catch.option=Ignore 'catch' block parameters method.names.differ.only.by.case.problem.descriptor=Method names #ref and ''{0}'' differ only by case #loc parameter.name.differs.from.overridden.parameter.ignore.character.option=Ignore if overridden parameter contains only one character parameter.name.differs.from.overridden.parameter.ignore.library.option=Ignore if overridden parameter is from a library @@ -1204,7 +1204,7 @@ transient.field.in.non.serializable.class.problem.descriptor=Field ''{0}'' is ma transient.field.in.non.serializable.class.remove.quickfix=Remove 'transient' condition.signal.replace.quickfix=Replace with 'signalAll()' object.notify.replace.quickfix=Replace with 'notifyAll()' -safe.lock.problem.descriptor=''{0}'' should be locked in front of a try block and unlocked in the corresponding finally block #loc +safe.lock.problem.descriptor=''{0}'' should be locked in front of a ''try'' block and unlocked in the corresponding ''finally'' block #loc synchronized.method.problem.descriptor=Method ''{0}()'' declared #ref #loc synchronized.method.include.option=Include native methods synchronized.method.move.quickfix=Move synchronization into method @@ -1213,12 +1213,12 @@ volatile.field.problem.descriptor=Volatile field #ref of type ''{0} exception.class.column.name=Exception class bad.exception.thrown.problem.descriptor=Prohibited exception ''{0}'' thrown #loc empty.catch.block.comments.option=Comments count as content -empty.catch.block.ignore.option=Ignore empty catch blocks in tests -empty.catch.block.ignore.ignore.option=Ignore for catch parameters named 'ignore' or 'ignored' -too.broad.catch.problem.descriptor=Catch of #ref is too broad, masking exception ''{0}'' #loc -too.broad.catch.problem.descriptor1=Catch of #ref is too broad, masking exceptions ''{0}'' and ''{1}'' #loc -unused.catch.parameter.ignore.catch.option=Ignore for catch blocks containing comments -unused.catch.parameter.ignore.empty.option=Ignore unused catch parameters in tests +empty.catch.block.ignore.option=Ignore empty 'catch' blocks in tests +empty.catch.block.ignore.ignore.option=Ignore for 'catch' parameters named 'ignore' or 'ignored' +too.broad.catch.problem.descriptor=''catch'' of #ref is too broad, masking exception ''{0}'' #loc +too.broad.catch.problem.descriptor1=''catch'' of #ref is too broad, masking exceptions ''{0}'' and ''{1}'' #loc +unused.catch.parameter.ignore.catch.option=Ignore for 'catch' blocks containing comments +unused.catch.parameter.ignore.empty.option=Ignore unused 'catch' parameters in tests add.serialversionuidfield.quickfix=Add 'serialVersionUID' field delete.import.quickfix=Delete unnecessary import encapsulate.variable.quickfix=Encapsulate variable @@ -1382,7 +1382,7 @@ create.documentation.couldnt.cast.class=Couldn''t cast {0} create.documentation.inspections.enabled.by.default.message=Inspections enabled by default: create.documentation.couldnt.find.documentation.file.error.message=Couldn''t find documentation file: {0} create.documentation.unused.documentation.file.error.message=Unused documentation file: {0} -assignment.to.catch.block.parameter.problem.descriptor=Assignment to catch block parameter #ref #loc +assignment.to.catch.block.parameter.problem.descriptor=Assignment to 'catch' block parameter #ref #loc assignment.to.method.parameter.problem.descriptor=Assignment to method parameter #ref #loc value.of.post.increment.problem.descriptor=Value of post-increment expression #ref is used #loc value.of.post.decrement.problem.descriptor=Value of post-decrement expression #ref is used #loc @@ -1558,7 +1558,7 @@ constant.string.intern.quickfix=Remove '.intern()' class.extends.utility.class.display.name=Class extends utility class class.extends.utility.class.problem.descriptor=Class #ref extends utility class ''{0}'' #loc public.constructor.in.non.public.class.quickfix=Make constructor ''{0}'' -assignment.to.method.parameter.ignore.transformation.option=Ignore if assignment is a transformation of the original parameter +assignment.to.method.parameter.ignore.transformation.option=Ignore if assignment is a transformation of the original parameter type.parameter.extends.final.class.display.name=Type parameter extends final class type.parameter.extends.final.class.problem.descriptor1=Type parameter #ref extends final class ''{0}'' #loc type.parameter.extends.final.class.problem.descriptor2=Wildcard type argument #ref extends final class ''{0}'' #loc @@ -1647,14 +1647,14 @@ ignore.guard.clauses=Ignore &guard clauses ignore.for.equals.methods=Ignore for &equals() methods caught.exception.immediately.rethrown.display.name=Caught exception is immediately rethrown caught.exception.immediately.rethrown.problem.descriptor=Caught exception #ref is immediately rethrown #loc -delete.catch.section.quickfix=Delete catch section -remove.try.catch.quickfix=Remove try-catch statement +delete.catch.section.quickfix=Delete 'catch' section +remove.try.catch.quickfix=Remove 'try catch' statement loop.with.implicit.termination.condition.display.name=Loop with implicit termination condition loop.with.implicit.termination.condition.dowhile.problem.descriptor=#ref-while loop with implicit termination condition #loc loop.with.implicit.termination.condition.problem.descriptor=#ref loop with implicit termination condition #loc loop.with.implicit.termination.condition.quickfix=Make condition explicit ignore.iterator.loop.variables=Ignore java.util.Iterator loop variables -rename.catch.parameter.to.ignored=Rename catch parameter to 'ignored' +rename.catch.parameter.to.ignored=Rename 'catch' parameter to 'ignored' unnecessary.super.qualifier.display.name=Unnecessary 'super' qualifier unnecessary.super.qualifier.problem.descriptor=Qualifier #ref is unnecessary in this context #loc unnecessary.super.qualifier.quickfix=Remove unnecessary 'super.' @@ -1664,7 +1664,7 @@ collections.field.access.replaceable.by.method.call.quickfix=Replace with ''{0}' synchronization.on.local.variable.or.method.parameter.display.name=Synchronization on local variable or method parameter synchronization.on.local.variable.problem.descriptor=Synchronization on local variable #ref #loc synchronization.on.method.parameter.problem.descriptor=Synchronization on method parameter #ref #loc -too.broad.catch.quickfix=Add catch clause for ''{0}'' +too.broad.catch.quickfix=Add ''catch'' clause for ''{0}'' too.broad.catch.option=&Only warn on RuntimeException, Exception, Error or Throwable unnecessary.call.to.string.valueof.display.name=Unnecessary call to 'String.valueOf()' unnecessary.call.to.string.valueof.problem.descriptor=#ref can be simplified to ''{0}'' #loc @@ -1710,9 +1710,9 @@ unnecessary.parentheses.conditional.option=Ignore parentheses around the conditi field.may.be.final.display.name=Field may be final field.may.be.final.problem.descriptor=Field #ref may be 'final' #loc cast.that.loses.precision.option=Ignore casts from int to char -variable.not.used.inside.if.display.name=Reference checked for null is not used inside if +variable.not.used.inside.if.display.name=Reference checked for 'null' is not used inside 'if' variable.not.used.inside.if.problem.descriptor=#ref is not used inside if #loc -if.may.be.conditional.display.name=If statement could be replaced with simple conditional expression +if.may.be.conditional.display.name='if' statement could be replaced with simple conditional expression if.may.be.conditional.problem.descriptor=#ref could be replaced with simple conditional expression #loc if.may.be.conditional.quickfix=Replace with conditional expression redundant.string.format.call.display.name=Redundant call to 'String.format()' @@ -1759,8 +1759,8 @@ unnecessary.javadoc.link.this.class.problem.descriptor=#ref pointin unnecessary.javadoc.link.quickfix=Remove unnecessary '{0}' thread.local.not.static.final.display.name=ThreadLocal field not declared static final thread.local.not.static.final.problem.descriptor=ThreadLocal #ref is not declared 'static final' #loc -remove.try.finally.block.quickfix=Remove try-finally block -remove.finally.block.quickfix=Remove finally block +remove.try.finally.block.quickfix=Remove 'try-finally' block +remove.finally.block.quickfix=Remove 'finally' block remove.leading.zero.to.make.decimal.quickfix=Remove leading zero to make decimal convert.octal.literal.to.decimal.literal.quickfix=Convert octal literal to decimal literal ignore.single.field.static.imports.option=Ignore single &field static imports @@ -1772,7 +1772,7 @@ ignored.io.resource.types=Ignored I/O resource types choose.io.resource.type.to.ignore=Choose I/O resource type to ignore ignore.accesses.from.the.same.class=Ignore accesses from the same class ignore.accesses.from.equals.method=Ignore accesses from 'equals()' method -ignore.branches.of.switch.statements=Ignore branches of switch statements +ignore.branches.of.switch.statements=Ignore branches of 'switch' statements ignore.equals.hashcode.and.tostring=Ignore equals, hashCode and toString methods class.name=Class name method.name.pattern=Method name pattern @@ -1802,8 +1802,8 @@ assertequals.called.on.arrays.display.name='assertEquals()' called on array assertequals.called.on.arrays.problem.descriptor=#ref() called on array #loc assertequals.called.on.arrays.quickfix=Replace with 'assertArrayEquals()' overly.broad.throws.clause.display.name=Overly broad 'throws' clause -overly.broad.throws.clause.problem.descriptor1=Throws of #ref is too broad, masking exception ''{0}'' #loc -overly.broad.throws.clause.problem.descriptor2=Throws of #ref is too broad, masking exceptions ''{0}'' and ''{1}'' #loc +overly.broad.throws.clause.problem.descriptor1=throws #ref is too broad, masking exception ''{0}'' #loc +overly.broad.throws.clause.problem.descriptor2=throws #ref is too broad, masking exceptions ''{0}'' and ''{1}'' #loc overly.broad.throws.clause.quickfix1=Add specific exceptions overly.broad.throws.clause.quickfix2=Replace with specific exceptions unnecessarily.qualified.statically.imported.element.display.name=Unnecessarily qualified statically imported element @@ -1811,14 +1811,14 @@ unnecessarily.qualified.statically.imported.element.problem.descriptor=Staticall unnecessarily.qualified.statically.imported.element.quickfix=Remove unnecessary qualifier ignore.instanceof.on.library.classes=Ignore instanceof on library classes assertequals.may.be.assertsame.quickfix=Replace with 'assertSame()' -for.can.be.foreach.option=Report indexed java.util.List loops +for.can.be.foreach.option=Report indexed 'java.util.List' loops cast.conflicts.with.instanceof.quickfix1=Replace cast to ''{0}'' with ''{1}'' cast.conflicts.with.instanceof.quickfix2=Replace instanceof ''{0}'' with ''{1}'' double.checked.locking.quickfix=Make ''{0}'' 'volatile' double.literal.may.be.float.literal.display.name='double' literal cast to 'float' could be 'float' literal double.literal.may.be.float.literal.problem.descriptor=#ref could be replaced with ''{0}'' #loc double.literal.may.be.float.literal.quickfix=Replace with ''{0}'' -multiple.declaration.option=Ignore for loop declarations +multiple.declaration.option=Ignore 'for' loop declarations simplifiable.annotation.display.name=Simplifiable annotation simplifiable.annotation.problem.descriptor=Annotation #ref may be replaced with ''{0}'' simplifiable.annotation.quickfix=Simplify annotation @@ -1851,3 +1851,8 @@ if.can.be.switch.display.name='if' replaceable with 'switch' if.can.be.switch.problem.descriptor=#ref statement replaceable with 'switch' statement if.can.be.switch.quickfix=Replace with 'switch' if.can.be.switch.minimum.branch.option=Minimum number of branches +if.can.be.switch.int.option=Suggest switch on int +if.can.be.switch.enum.option=Suggest switch on enum +unnecessarily.qualified.inner.class.access.option=Ignore references to foreign inner classes +unqualified.inner.class.access.option=Ignore references to local inner classes +try.with.identical.catches.quickfix=Collapse catch blocks into multi-catch diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java index 5deb22cc2a72..1d20d6af62f1 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java @@ -74,7 +74,7 @@ public abstract class BaseInspection extends BaseJavaLocalInspectionTool { packageGroupDisplayNameMap.put("javabeans", GroupNames.JAVABEANS_GROUP_NAME); packageGroupDisplayNameMap.put("javadoc", GroupNames.JAVADOC_GROUP_NAME); packageGroupDisplayNameMap.put("jdk", GroupNames.JDK_GROUP_NAME); - packageGroupDisplayNameMap.put("jdk15", GroupNames.LANGUAGE_LEVEL_SPECIFIC_GROUP_NAME); + packageGroupDisplayNameMap.put("migration", GroupNames.LANGUAGE_LEVEL_SPECIFIC_GROUP_NAME); packageGroupDisplayNameMap.put("junit", GroupNames.JUNIT_GROUP_NAME); packageGroupDisplayNameMap.put("logging", GroupNames.LOGGING_GROUP_NAME); packageGroupDisplayNameMap.put("maturity", GroupNames.MATURITY_GROUP_NAME); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java index 5c6a5b9a75b1..c41a237911c1 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java @@ -58,7 +58,7 @@ import com.siyeh.ig.javadoc.PackageDotHtmlMayBePackageInfoInspection; import com.siyeh.ig.javadoc.UnnecessaryInheritDocInspection; import com.siyeh.ig.javadoc.UnnecessaryJavaDocLinkInspection; import com.siyeh.ig.jdk.*; -import com.siyeh.ig.jdk15.*; +import com.siyeh.ig.migration.*; import com.siyeh.ig.junit.*; import com.siyeh.ig.logging.*; import com.siyeh.ig.maturity.*; @@ -296,7 +296,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent, registerJ2MEInspections(); registerJavaBeansInspections(); registerJavadocInspections(); - registerJdk5SpecificInspections(); + registerLanguageLevelMigrationInspections(); registerJdkInspections(); registerJUnitInspections(); registerLoggingInspections(); @@ -481,7 +481,6 @@ public class InspectionGadgetsPlugin implements ApplicationComponent, m_inspectionClasses.add(FallthruInSwitchStatementInspection.class); m_inspectionClasses.add(ForLoopReplaceableByWhileInspection.class); m_inspectionClasses.add(ForLoopWithMissingComponentInspection.class); - m_inspectionClasses.add(IfCanBeSwitchInspection.class); m_inspectionClasses.add(IfMayBeConditionalInspection.class); m_inspectionClasses.add(IfStatementWithIdenticalBranchesInspection.class); m_inspectionClasses.add(IfStatementWithTooManyBranchesInspection.class); @@ -625,10 +624,11 @@ public class InspectionGadgetsPlugin implements ApplicationComponent, m_inspectionClasses.add(ReplaceAssignmentWithOperatorAssignmentInspection.class); } - private void registerJdk5SpecificInspections() { + private void registerLanguageLevelMigrationInspections() { m_inspectionClasses.add(CollectionsFieldAccessReplaceableByMethodCallInspection .class); m_inspectionClasses.add(ForCanBeForeachInspection.class); m_inspectionClasses.add(EnumerationCanBeIterationInspection.class); + m_inspectionClasses.add(IfCanBeSwitchInspection.class); m_inspectionClasses.add(IndexOfReplaceableByContainsInspection.class); m_inspectionClasses.add(RawUseOfParameterizedTypeInspection.class); m_inspectionClasses.add(UnnecessaryBoxingInspection.class); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java index 0d6393f5dd24..696cfbb905fd 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 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. @@ -18,7 +18,11 @@ package com.siyeh.ig.controlflow; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.extractMethod.InputVariables; +import com.intellij.refactoring.util.duplicates.DuplicatesFinder; +import com.intellij.refactoring.util.duplicates.Match; import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -29,6 +33,8 @@ import com.siyeh.ig.psiutils.EquivalenceChecker; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; + public class IfStatementWithIdenticalBranchesInspection extends BaseInspection{ @@ -151,48 +157,50 @@ public class IfStatementWithIdenticalBranchesInspection private static class IfStatementWithIdenticalBranchesVisitor extends BaseInspectionVisitor{ - private static final int LIMIT_DEPTH = 20; // Dirty fix for 'squared' algorithm. + private static final int LIMIT_DEPTH = 20; // Dirty fix for 'squared' algorithm. - @Override public void visitIfStatement( + @Override public void visitIfStatement( @NotNull PsiIfStatement ifStatement){ super.visitIfStatement(ifStatement); - final PsiStatement thenBranch = ifStatement.getThenBranch(); PsiStatement elseBranch = ifStatement.getElseBranch(); + final PsiStatement thenBranch = ifStatement.getThenBranch(); if (thenBranch == null) { return; } - if (elseBranch == null) { - checkIfStatementWithoutElseBranch(ifStatement); - return; - } - if (EquivalenceChecker.statementsAreEquivalent( - thenBranch, elseBranch)) { - registerStatementError(ifStatement); - return; - } - final PsiStatement identicalElseIf = - getIdenticalElseIfStatement(thenBranch, elseBranch); - if (identicalElseIf == null) { - return; - } - registerStatementError(ifStatement, identicalElseIf); - } - - public static PsiStatement getIdenticalElseIfStatement( - PsiStatement thenBranch, PsiStatement elseBranch) { + final Project project = ifStatement.getProject(); + final InputVariables inputVariables = + new InputVariables(Collections.emptyList(), + project, new LocalSearchScope(thenBranch), false); + final DuplicatesFinder finder = + new DuplicatesFinder(new PsiElement[]{thenBranch}, + inputVariables, null, + Collections.emptyList()); int depth = 0; while (elseBranch instanceof PsiIfStatement) { - if (depth++ > LIMIT_DEPTH) break; + if (depth++ > LIMIT_DEPTH) { + break; + } final PsiIfStatement statement = (PsiIfStatement) elseBranch; final PsiStatement branch = statement.getThenBranch(); - if (EquivalenceChecker.statementsAreEquivalent( - thenBranch, branch)) { - return statement; + if (branch == null) { + return; + } + final Match match = finder.isDuplicate(branch, true); + if (match != null) { + registerStatementError(ifStatement, statement); + return; } elseBranch = statement.getElseBranch(); } - return null; + if (elseBranch == null) { + checkIfStatementWithoutElseBranch(ifStatement); + } else { + final Match match = finder.isDuplicate(elseBranch, true); + if (match != null) { + registerStatementError(ifStatement); + } + } } private void checkIfStatementWithoutElseBranch( diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TooBroadCatchInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TooBroadCatchInspection.java index 4056e04fd021..c66abe60aecd 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TooBroadCatchInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TooBroadCatchInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 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. @@ -16,6 +16,7 @@ package com.siyeh.ig.errorhandling; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; @@ -30,14 +31,10 @@ import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.ExceptionUtils; -import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import org.jetbrains.annotations.NotNull; -import javax.swing.JComponent; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import javax.swing.*; +import java.util.*; public class TooBroadCatchInspection extends BaseInspection { @@ -204,29 +201,58 @@ public class TooBroadCatchInspection extends BaseInspection { continue; } final PsiType typeCaught = parameter.getType(); - if (exceptionsThrown.contains(typeCaught)) { - exceptionsCaught.add(typeCaught); - } - final List typesMasked = new ArrayList(); - for (PsiType typeThrown : exceptionsThrown) { - if (!exceptionsCaught.contains(typeThrown) && - typeCaught.isAssignableFrom(typeThrown)) { - exceptionsCaught.add(typeThrown); - typesMasked.add(typeThrown); + if (typeCaught instanceof PsiDisjunctionType) { + final PsiDisjunctionType disjunctionType = + (PsiDisjunctionType) typeCaught; + final List types = + disjunctionType.getDisjunctions(); + for (PsiType type : types) { + final List maskedExceptions = + findMaskedExceptions(exceptionsThrown, + exceptionsCaught, type); + if (!maskedExceptions.isEmpty()) { + final PsiTypeElement typeElement = + parameter.getTypeElement(); + registerError(typeElement, maskedExceptions, + statement, catchSection); + } + } + } else { + final List maskedExceptions = + findMaskedExceptions(exceptionsThrown, + exceptionsCaught, typeCaught); + if (!maskedExceptions.isEmpty()) { + final PsiTypeElement typeElement = + parameter.getTypeElement(); + registerError(typeElement, maskedExceptions, statement, + catchSection); } } - if (onlyWarnOnRootExceptions) { - if (!ExceptionUtils.isGenericExceptionClass(typeCaught)) { - continue; - } - } - if (!typesMasked.isEmpty()) { - final PsiTypeElement typeElement = - parameter.getTypeElement(); - registerError(typeElement, typesMasked, statement, - catchSection); + + } + } + + private List findMaskedExceptions( + Set exceptionsThrown, + Set exceptionsCaught, PsiType typeCaught) { + if (exceptionsThrown.contains(typeCaught)) { + exceptionsCaught.add(typeCaught); + exceptionsThrown.remove(typeCaught); + } + final List typesMasked = new ArrayList(); + for (PsiType typeThrown : exceptionsThrown) { + if (!exceptionsCaught.contains(typeThrown) && + typeCaught.isAssignableFrom(typeThrown)) { + exceptionsCaught.add(typeThrown); + typesMasked.add(typeThrown); } } + if (onlyWarnOnRootExceptions) { + if (!ExceptionUtils.isGenericExceptionClass(typeCaught)) { + return Collections.EMPTY_LIST; + } + } + return typesMasked; } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TryWithIdenticalCatchesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TryWithIdenticalCatchesInspection.java index bfe4f41616b5..f707b9229178 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TryWithIdenticalCatchesInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TryWithIdenticalCatchesInspection.java @@ -30,6 +30,7 @@ import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.util.Collections; @@ -83,17 +84,23 @@ public class TryWithIdenticalCatchesInspection extends BaseInspection { boolean[] duplicates = new boolean[catchSections.length]; for (int i = 0; i < catchSections.length; i++) { if (duplicates[i]) continue; - InputVariables inputVariables = new InputVariables(Collections.singletonList(catchSections[i].getParameter()), + final PsiCatchSection catchSection = catchSections[i]; + final PsiCodeBlock catchBlock = catchSection.getCatchBlock(); + if (catchBlock == null) continue; + InputVariables inputVariables = new InputVariables(Collections.singletonList(catchSection.getParameter()), statement.getProject(), - new LocalSearchScope(catchSections[i].getCatchBlock()), + new LocalSearchScope(catchBlock), false); - DuplicatesFinder finder = new DuplicatesFinder(new PsiElement[] { catchSections [i].getCatchBlock() }, + DuplicatesFinder finder = new DuplicatesFinder(new PsiElement[] {catchBlock}, inputVariables, null, Collections.emptyList()); for (int j = 0; j < catchSections.length; j++) { if (i == j || duplicates[j]) continue; - Match match = finder.isDuplicate(catchSections[j].getCatchBlock(), true); + final PsiCatchSection otherSection = catchSections[j]; + final PsiCodeBlock otherCatchBlock = otherSection.getCatchBlock(); + if (otherCatchBlock == null) continue; + Match match = finder.isDuplicate(otherCatchBlock, true); if (match != null) { - registerError(catchSections[j], i); + registerError(otherSection, i); duplicates[i] = true; duplicates[j] = true; } @@ -123,16 +130,15 @@ public class TryWithIdenticalCatchesInspection extends BaseInspection { if (parameter1 == null || parameter2 == null) { return; } - String text = "try { } catch(" + parameter1.getTypeElement().getText() + " | " + parameter2.getTypeElement().getText() + " e) { }"; + @NonNls String text = "try { } catch(" + parameter1.getTypeElement().getText() + " | " + parameter2.getTypeElement().getText() + " e) { }"; PsiTryStatement newTryCatch = (PsiTryStatement)JavaPsiFacade.getElementFactory(project).createStatementFromText(text, stmt); parameter1.getTypeElement().replace(newTryCatch.getCatchSections() [0].getParameter().getTypeElement()); section.delete(); } @NotNull - @Override public String getName() { - return"Collapse catch blocks into multi-catch"; + return InspectionGadgetsBundle.message("try.with.identical.catches.quickfix"); } } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/CollectionsFieldAccessReplaceableByMethodCallInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/CollectionsFieldAccessReplaceableByMethodCallInspection.java similarity index 99% rename from plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/CollectionsFieldAccessReplaceableByMethodCallInspection.java rename to plugins/InspectionGadgets/src/com/siyeh/ig/migration/CollectionsFieldAccessReplaceableByMethodCallInspection.java index dda2605db29e..5390fe0d939c 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/CollectionsFieldAccessReplaceableByMethodCallInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/CollectionsFieldAccessReplaceableByMethodCallInspection.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/EnumerationCanBeIterationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/EnumerationCanBeIterationInspection.java similarity index 99% rename from plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/EnumerationCanBeIterationInspection.java rename to plugins/InspectionGadgets/src/com/siyeh/ig/migration/EnumerationCanBeIterationInspection.java index 7d56268a6a55..4845a85b74a4 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/EnumerationCanBeIterationInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/EnumerationCanBeIterationInspection.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/ForCanBeForeachInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java similarity index 99% rename from plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/ForCanBeForeachInspection.java rename to plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java index f8f3b37f7a87..c88e5d45ee81 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/ForCanBeForeachInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfCanBeSwitchInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java similarity index 84% rename from plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfCanBeSwitchInspection.java rename to plugins/InspectionGadgets/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java index 1c4a722745c5..5b2c1d0925c6 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfCanBeSwitchInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.controlflow; +package com.siyeh.ig.migration; import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.codeInspection.ui.SingleIntegerFieldOptionsPanel; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.ui.DocumentAdapter; import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -35,6 +35,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.text.Document; +import java.awt.*; +import java.text.NumberFormat; +import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -43,6 +50,12 @@ public class IfCanBeSwitchInspection extends BaseInspection { @SuppressWarnings({"PublicField"}) public int minimumBranches = 3; + @SuppressWarnings({"PublicField"}) + public boolean suggestIntSwitches = false; + + @SuppressWarnings({"PublicField"}) + public boolean suggestEnumSwitches = false; + @Nls @NotNull @Override @@ -64,10 +77,67 @@ public class IfCanBeSwitchInspection extends BaseInspection { @Override public JComponent createOptionsPanel() { - return new SingleIntegerFieldOptionsPanel( - InspectionGadgetsBundle.message( - "if.can.be.switch.minimum.branch.option"), - this, "minimumBranches"); + final JPanel panel = new JPanel(new GridBagLayout()); + final JLabel label = new JLabel(InspectionGadgetsBundle.message( + "if.can.be.switch.minimum.branch.option")); + final NumberFormat formatter = NumberFormat.getIntegerInstance(); + formatter.setParseIntegerOnly(true); + final JFormattedTextField valueField = + new JFormattedTextField(formatter); + valueField.setValue(Integer.valueOf(minimumBranches)); + valueField.setColumns(2); + final Document document = valueField.getDocument(); + document.addDocumentListener(new DocumentAdapter() { + @Override + public void textChanged(DocumentEvent e) { + try { + valueField.commitEdit(); + minimumBranches = + ((Number) valueField.getValue()).intValue(); + } catch (ParseException e1) { + // No luck this time + } + } + }); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.insets.left = 4; + constraints.insets.top = 4; + constraints.weightx = 0.0; + constraints.anchor = GridBagConstraints.BASELINE_LEADING; + constraints.fill = GridBagConstraints.NONE; + panel.add(label, constraints); + constraints.gridx = 1; + constraints.gridy = 0; + constraints.weightx = 1.0; + panel.add(valueField, constraints); + constraints.gridx = 0; + constraints.gridy = 1; + constraints.gridwidth = 2; + final JCheckBox checkBox1 = new JCheckBox( + InspectionGadgetsBundle.message("if.can.be.switch.int.option"), + suggestIntSwitches); + final ButtonModel model1 = checkBox1.getModel(); + model1.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + suggestIntSwitches = model1.isSelected(); + } + }); + panel.add(checkBox1, constraints); + constraints.gridy = 2; + constraints.weighty = 1.0; + final JCheckBox checkBox2 = new JCheckBox( + InspectionGadgetsBundle.message("if.can.be.switch.enum.option"), + suggestEnumSwitches); + final ButtonModel model2 = checkBox2.getModel(); + model2.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + suggestEnumSwitches = model2.isSelected(); + } + }); + panel.add(checkBox2, constraints); + return panel; } private static class IfCanBeSwitchFix extends InspectionGadgetsFix { @@ -453,6 +523,17 @@ public class IfCanBeSwitchInspection extends BaseInspection { if (switchExpression == null) { return; } + final PsiType type = switchExpression.getType(); + if (!suggestIntSwitches && PsiType.INT.equals(type)) { + return; + } + if (!suggestEnumSwitches && type instanceof PsiClassType) { + final PsiClassType classType = (PsiClassType) type; + final PsiClass aClass = classType.resolve(); + if (aClass == null || aClass.isEnum()) { + return; + } + } registerStatementError(statement, switchExpression); } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementBranch.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/IfStatementBranch.java similarity index 80% rename from plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementBranch.java rename to plugins/InspectionGadgets/src/com/siyeh/ig/migration/IfStatementBranch.java index 582ee9b4755e..78a05949d219 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementBranch.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/IfStatementBranch.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.controlflow; +package com.siyeh.ig.migration; import com.intellij.psi.*; import java.util.*; -class IfStatementBranch{ +class IfStatementBranch { private final Set topLevelVariables = new HashSet(3); private final LinkedList comments = new LinkedList(); @@ -34,7 +34,7 @@ class IfStatementBranch{ calculateVariablesDeclared(statement); } - public void addComment(String comment){ + public void addComment(String comment) { comments.addFirst(comment); } @@ -42,32 +42,32 @@ class IfStatementBranch{ statementComments.addFirst(comment); } - public void addCondition(String conditionString){ + public void addCondition(String conditionString) { conditions.add(conditionString); } - public PsiStatement getStatement(){ + public PsiStatement getStatement() { return statement; } - public List getConditions(){ + public List getConditions() { return Collections.unmodifiableList(conditions); } - public boolean isElse(){ + public boolean isElse() { return elseBranch; } public boolean topLevelDeclarationsConflictWith( - IfStatementBranch testBranch){ + IfStatementBranch testBranch) { final Set topLevel = testBranch.topLevelVariables; return intersects(topLevelVariables, topLevel); } private static boolean intersects(Set set1, - Set set2){ - for(final String s : set1){ - if(set2.contains(s)){ + Set set2) { + for (final String s : set1) { + if (set2.contains(s)) { return true; } } @@ -82,25 +82,25 @@ class IfStatementBranch{ return statementComments; } - public void calculateVariablesDeclared(PsiStatement statement){ - if(statement == null){ + public void calculateVariablesDeclared(PsiStatement statement) { + if (statement == null) { return; } - if(statement instanceof PsiDeclarationStatement){ + if (statement instanceof PsiDeclarationStatement) { final PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement) statement; final PsiElement[] elements = declarationStatement.getDeclaredElements(); - for(PsiElement element : elements){ + for (PsiElement element : elements) { final PsiVariable variable = (PsiVariable) element; final String varName = variable.getName(); topLevelVariables.add(varName); } - } else if(statement instanceof PsiBlockStatement){ + } else if (statement instanceof PsiBlockStatement) { final PsiBlockStatement block = (PsiBlockStatement) statement; final PsiCodeBlock codeBlock = block.getCodeBlock(); final PsiStatement[] statements = codeBlock.getStatements(); - for(PsiStatement statement1 : statements){ + for (PsiStatement statement1 : statements) { calculateVariablesDeclared(statement1); } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/IndexOfReplaceableByContainsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java similarity index 99% rename from plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/IndexOfReplaceableByContainsInspection.java rename to plugins/InspectionGadgets/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java index f8c46f80a7a3..c656f993a111 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/IndexOfReplaceableByContainsInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/RawUseOfParameterizedTypeInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java similarity index 99% rename from plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/RawUseOfParameterizedTypeInspection.java rename to plugins/InspectionGadgets/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java index 029f378ccaa2..ed73360db49c 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/RawUseOfParameterizedTypeInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.lang.StdLanguages; diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/UnnecessaryBoxingInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/UnnecessaryBoxingInspection.java similarity index 99% rename from plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/UnnecessaryBoxingInspection.java rename to plugins/InspectionGadgets/src/com/siyeh/ig/migration/UnnecessaryBoxingInspection.java index 46c65ed6d623..932f59af5063 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/UnnecessaryBoxingInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/UnnecessaryBoxingInspection.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/UnnecessaryUnboxingInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/UnnecessaryUnboxingInspection.java similarity index 99% rename from plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/UnnecessaryUnboxingInspection.java rename to plugins/InspectionGadgets/src/com/siyeh/ig/migration/UnnecessaryUnboxingInspection.java index 090092544f3e..0d8c1da0e178 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/UnnecessaryUnboxingInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/UnnecessaryUnboxingInspection.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/WhileCanBeForeachInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/WhileCanBeForeachInspection.java similarity index 99% rename from plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/WhileCanBeForeachInspection.java rename to plugins/InspectionGadgets/src/com/siyeh/ig/migration/WhileCanBeForeachInspection.java index 3472dff50aba..459326faac37 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/jdk15/WhileCanBeForeachInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/WhileCanBeForeachInspection.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessarilyQualifiedInnerClassAccessInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessarilyQualifiedInnerClassAccessInspection.java index a38eb211b874..6c3a57d5e184 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessarilyQualifiedInnerClassAccessInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessarilyQualifiedInnerClassAccessInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2010 Bas Leijdekkers + * Copyright 2010-2011 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,10 @@ package com.siyeh.ig.style; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -27,9 +29,14 @@ import com.siyeh.ig.psiutils.ImportUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import javax.swing.*; + public class UnnecessarilyQualifiedInnerClassAccessInspection extends BaseInspection { + @SuppressWarnings({"PublicField"}) + public boolean ignoreReferencesToForeignInnerClasses = false; + @Nls @NotNull @Override @@ -47,6 +54,14 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection aClass.getName()); } + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel( + InspectionGadgetsBundle.message( + "unnecessarily.qualified.inner.class.access.option"), + this, "ignoreReferencesToForeignInnerClasses"); + } + @Override protected InspectionGadgetsFix buildFix(Object... infos) { return new UnnecessarilyQualifiedInnerClassAccessFix(); @@ -90,7 +105,7 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection return new UnnecessarilyQualifiedInnerClassAccessVisitor(); } - private static class UnnecessarilyQualifiedInnerClassAccessVisitor + private class UnnecessarilyQualifiedInnerClassAccessVisitor extends BaseInspectionVisitor { @Override @@ -116,6 +131,20 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection if (!(qualifierTarget instanceof PsiClass)) { return; } + final PsiClass referenceClass = + PsiTreeUtil.getParentOfType(reference, PsiClass.class); + if (referenceClass == null) { + return; + } + if (!referenceClass.equals(qualifierTarget)) { + if (PsiTreeUtil.isAncestor(referenceClass, qualifierTarget, + true) || + (ignoreReferencesToForeignInnerClasses && + !PsiTreeUtil.isAncestor(qualifierTarget, + referenceClass, true))) { + return; + } + } final PsiElement target = reference.resolve(); if (!(target instanceof PsiClass)) { return; @@ -141,7 +170,7 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection visitReferenceElement(expression); } - private static boolean isReferenceToTarget( + private boolean isReferenceToTarget( String referenceText, PsiClass target, PsiElement context) { final PsiManager manager = target.getManager(); final JavaPsiFacade facade = @@ -150,13 +179,11 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection final PsiClass referencedClass = resolveHelper.resolveReferencedClass(referenceText, context); - if (referencedClass == null) { - return true; - } - return manager.areElementsEquivalent(target, referencedClass); + return referencedClass == null || + manager.areElementsEquivalent(target, referencedClass); } - private static boolean isInImportOrPackage(PsiElement element) { + private boolean isInImportOrPackage(PsiElement element) { while (element instanceof PsiJavaCodeReferenceElement) { element = element.getParent(); if (element instanceof PsiImportStatementBase || diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnqualifiedInnerClassAccessInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnqualifiedInnerClassAccessInspection.java index 01262754a49b..6580869f4b53 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnqualifiedInnerClassAccessInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnqualifiedInnerClassAccessInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2010 Bas Leijdekkers + * Copyright 2010-2011 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,11 @@ package com.siyeh.ig.style; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -29,10 +31,14 @@ import com.siyeh.ig.psiutils.ImportUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import javax.swing.*; import java.util.*; public class UnqualifiedInnerClassAccessInspection extends BaseInspection { + @SuppressWarnings({"PublicField"}) + public boolean ignoreReferencesToLocalInnerClasses = false; + @Nls @NotNull @Override @@ -48,6 +54,14 @@ public class UnqualifiedInnerClassAccessInspection extends BaseInspection { "unqualified.inner.class.access.problem.descriptor"); } + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel( + InspectionGadgetsBundle.message( + "unqualified.inner.class.access.option"), + this, "ignoreReferencesToLocalInnerClasses"); + } + @Override protected InspectionGadgetsFix buildFix(Object... infos) { return new UnqualifiedInnerClassAccessFix(); @@ -146,7 +160,8 @@ public class UnqualifiedInnerClassAccessInspection extends BaseInspection { ImportUtils.addImportIfNeeded(javaFile, containingClass); final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); - final Document document = documentManager.getDocument(containingFile); + final Document document = + documentManager.getDocument(containingFile); if (document == null) { return; } @@ -194,13 +209,15 @@ public class UnqualifiedInnerClassAccessInspection extends BaseInspection { } private static boolean isReferenceToTargetClass( - String referenceText, PsiClass targetClass, PsiElement context) { + String referenceText, PsiClass targetClass, + PsiElement context) { final PsiManager manager = targetClass.getManager(); final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); final PsiResolveHelper resolveHelper = facade.getResolveHelper(); final PsiClass referencedClass = - resolveHelper.resolveReferencedClass(referenceText, context); + resolveHelper.resolveReferencedClass(referenceText, + context); if (referencedClass == null) { return true; } @@ -208,7 +225,8 @@ public class UnqualifiedInnerClassAccessInspection extends BaseInspection { } } - private static class ReferenceCollector extends JavaRecursiveElementVisitor { + private static class ReferenceCollector + extends JavaRecursiveElementVisitor { private final String name; private final boolean onDemand; @@ -265,7 +283,7 @@ public class UnqualifiedInnerClassAccessInspection extends BaseInspection { return new UnqualifiedInnerClassAccessVisitor(); } - private static class UnqualifiedInnerClassAccessVisitor + private class UnqualifiedInnerClassAccessVisitor extends BaseInspectionVisitor { @Override @@ -284,12 +302,24 @@ public class UnqualifiedInnerClassAccessInspection extends BaseInspection { if (containingClass == null) { return; } + if (ignoreReferencesToLocalInnerClasses) { + if (PsiTreeUtil.isAncestor(containingClass, reference, true)) { + return; + } + final PsiClass referenceClass = + PsiTreeUtil.getParentOfType(reference, PsiClass.class); + if (PsiTreeUtil.isAncestor(referenceClass, containingClass, + true)) { + return; + } + } registerError(reference, containingClass.getName()); } - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - visitReferenceElement(expression); - } + @Override + public void visitReferenceExpression( + PsiReferenceExpression expression) { + visitReferenceElement(expression); + } } } diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TryWithIdenticalCatches.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TryWithIdenticalCatches.html index 887abc484396..85514604f59d 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/TryWithIdenticalCatches.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TryWithIdenticalCatches.html @@ -2,6 +2,6 @@ This inspection reports identical 'catch' sections in 'try' blocks under JDK 7. A quickfix is provided to collapse the sections into a multi-catch section. -Powered by InspectionGadgets +

Powered by InspectionGadgets \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarilyQualifiedInnerClassAccess.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarilyQualifiedInnerClassAccess.html index 5d94579c09ba..d29db28c7692 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarilyQualifiedInnerClassAccess.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarilyQualifiedInnerClassAccess.html @@ -1,7 +1,11 @@ This inspection reports any references to inner classes which are unnecessarily qualified with the name -of the enclosing class. Such qualification is unnecessary, and may be safely removed. +of the enclosing class. Such qualification is unnecessary, and may be safely removed. This may +require the addition of an import for the inner class. +

+Use the checkbox below to ignore references to inner classes where the removal of the qualification +would require the addition of an import.

New in 10, Powered by InspectionGadgets diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnqualifiedInnerClassAccess.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnqualifiedInnerClassAccess.html index 3776625d5513..77f370cfc018 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/UnqualifiedInnerClassAccess.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnqualifiedInnerClassAccess.html @@ -3,6 +3,8 @@ This inspection reports any references to inner classes which are not qualified with the name of the enclosing class.

+Use the checkbox below to ignore references to local inner classes that do not require an import. +

New in 10, Powered by InspectionGadgets \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java new file mode 100644 index 000000000000..aa3f6ac30def --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java @@ -0,0 +1,102 @@ +package com.siyeh.igtest.controlflow.if_statement_with_identical_branches; + +public class IfStatementWithIdenticalBranches { + + void one() { + if (true) { + + } else { + + } + if (false) { + System.out.println(); + return; + } + System.out.println(); + } + + int two() { + if (true) { + int i = 2; + return i; + } else { + int j = 2; + return j; + } + } + + int three() { + if (true) { + int i = 3; + return i; + } else { + int j = 4; + return j; + } + } + + void four() { + if (true) { + if (false) { + System.out.println(); + return; + } + } + System.out.println(); + } + + void five() { + boolean b = true; + while (b) { + if (true) { + System.out.println(); + } + } + System.out.println(); + } + + void six() { + if (true) { + if (false) { + System.out.println(); + System.out.println(); + return; + } + System.out.println(); + } + System.out.println(); + } + + void seven() { + if (true) { + System.out.println(); + return; + } else if (true) { + System.out.println("different"); + return; + } + System.out.println(); + } + + void eight() { + if (true) { + System.out.println(); + } else if (true) { + System.out.println("different"); + } else { + System.out.println(); + } + } + + void nine() { + if (true) { + + } else if (true) { + + } else if (true) { + + } else { + + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/expected.xml new file mode 100644 index 000000000000..09413c6c0692 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/expected.xml @@ -0,0 +1,72 @@ + + + + IfStatementWithIdenticalBranches.java + 6 + 'if' statement with identical branches + <code>if</code> statement with identical branches #loc + + + + IfStatementWithIdenticalBranches.java + 11 + 'if' statement with identical branches + <code>if</code> statement with identical branches #loc + + + + IfStatementWithIdenticalBranches.java + 19 + 'if' statement with identical branches + <code>if</code> statement with identical branches #loc + + + + IfStatementWithIdenticalBranches.java + 40 + 'if' statement with identical branches + <code>if</code> statement with identical branches #loc + + + + IfStatementWithIdenticalBranches.java + 60 + 'if' statement with identical branches + <code>if</code> statement with identical branches #loc + + + + IfStatementWithIdenticalBranches.java + 71 + 'if' statement with identical branches + <code>if</code> statement with identical branches #loc + + + + IfStatementWithIdenticalBranches.java + 82 + 'if' statement with identical branches + <code>if</code> statement with identical branches #loc + + + + IfStatementWithIdenticalBranches.java + 92 + 'if' statement with identical branches + <code>if</code> statement with identical branches #loc + + + + IfStatementWithIdenticalBranches.java + 94 + 'if' statement with identical branches + <code>if</code> statement with identical branches #loc + + + + IfStatementWithIdenticalBranches.java + 96 + 'if' statement with identical branches + <code>if</code> statement with identical branches #loc + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/toobroadcatch/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/toobroadcatch/expected.xml index 55b425d76f7b..b93f86c4aaad 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/toobroadcatch/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/toobroadcatch/expected.xml @@ -5,27 +5,27 @@ TooBroadCatchBlock.java 18 Overly broad 'catch' block - Catch of <code>IOException</code> is too broad, masking exception 'EOFException' #loc + ''catch'' of <code>IOException</code> is too broad, masking exception 'EOFException' #loc TooBroadCatchBlock.java 31 Overly broad 'catch' block - Catch of <code>IOException</code> is too broad, masking exception 'MalformedURLException' #loc + ''catch'' of <code>IOException</code> is too broad, masking exception 'MalformedURLException' #loc TooBroadCatchBlock.java 33 Overly broad 'catch' block - Catch of <code>RuntimeException</code> is too broad, masking exception 'NullPointerException' #loc + ''catch'' of <code>RuntimeException</code> is too broad, masking exception 'NullPointerException' #loc TooBroadCatchBlock.java 49 Overly broad 'catch' block - Catch of <code>ObjectStreamException</code> is too broad, masking exceptions 'NotActiveException' and 'StreamCorruptedException' #loc + ''catch'' of <code>ObjectStreamException</code> is too broad, masking exceptions 'NotActiveException' and 'StreamCorruptedException' #loc \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/EnumerationCanBeIterationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/EnumerationCanBeIterationInspection.java similarity index 96% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/EnumerationCanBeIterationInspection.java rename to plugins/InspectionGadgets/test/com/siyeh/igtest/migration/EnumerationCanBeIterationInspection.java index a56cac6bb65d..d218c3beae74 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/EnumerationCanBeIterationInspection.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/EnumerationCanBeIterationInspection.java @@ -1,4 +1,4 @@ -package com.siyeh.igtest.jdk15; +package com.siyeh.igtest.migration; import java.util.Vector; import java.util.Hashtable; diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/foreach/ForCanBeForEach.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/foreach/ForCanBeForEach.java similarity index 99% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/foreach/ForCanBeForEach.java rename to plugins/InspectionGadgets/test/com/siyeh/igtest/migration/foreach/ForCanBeForEach.java index 8da347ac246b..51d5a37047fb 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/foreach/ForCanBeForEach.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/foreach/ForCanBeForEach.java @@ -1,4 +1,4 @@ -package com.siyeh.igtest.jdk15.foreach; +package com.siyeh.igtest.migration.foreach; import com.siyeh.igtest.verbose.OuterClass; diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/foreach/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/foreach/expected.xml similarity index 100% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/foreach/expected.xml rename to plugins/InspectionGadgets/test/com/siyeh/igtest/migration/foreach/expected.xml diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/unnecessary_boxing/UnnecessaryBoxing.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/unnecessary_boxing/UnnecessaryBoxing.java similarity index 96% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/unnecessary_boxing/UnnecessaryBoxing.java rename to plugins/InspectionGadgets/test/com/siyeh/igtest/migration/unnecessary_boxing/UnnecessaryBoxing.java index 70e5bf746ca0..a25f0bcdb679 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/unnecessary_boxing/UnnecessaryBoxing.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/unnecessary_boxing/UnnecessaryBoxing.java @@ -1,4 +1,4 @@ -package com.siyeh.igtest.jdk15.unnecessary_boxing; +package com.siyeh.igtest.migration.unnecessary_boxing; diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/unnecessary_boxing/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/unnecessary_boxing/expected.xml similarity index 100% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/unnecessary_boxing/expected.xml rename to plugins/InspectionGadgets/test/com/siyeh/igtest/migration/unnecessary_boxing/expected.xml diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/unnecessary_unboxing/UnnecessaryUnboxing.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/unnecessary_unboxing/UnnecessaryUnboxing.java similarity index 94% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/unnecessary_unboxing/UnnecessaryUnboxing.java rename to plugins/InspectionGadgets/test/com/siyeh/igtest/migration/unnecessary_unboxing/UnnecessaryUnboxing.java index d772cf1da396..d83a1f862083 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/unnecessary_unboxing/UnnecessaryUnboxing.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/unnecessary_unboxing/UnnecessaryUnboxing.java @@ -1,4 +1,4 @@ -package com.siyeh.igtest.jdk15.unnecessary_unboxing; +package com.siyeh.igtest.migration.unnecessary_unboxing; diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/unnecessary_unboxing/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/unnecessary_unboxing/expected.xml similarity index 100% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/unnecessary_unboxing/expected.xml rename to plugins/InspectionGadgets/test/com/siyeh/igtest/migration/unnecessary_unboxing/expected.xml diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/while_can_be_foreach/WhileCanBeForeachInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/while_can_be_foreach/WhileCanBeForeachInspection.java similarity index 96% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/while_can_be_foreach/WhileCanBeForeachInspection.java rename to plugins/InspectionGadgets/test/com/siyeh/igtest/migration/while_can_be_foreach/WhileCanBeForeachInspection.java index b6c5d5dbf840..1c7703507fe5 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/while_can_be_foreach/WhileCanBeForeachInspection.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/while_can_be_foreach/WhileCanBeForeachInspection.java @@ -1,4 +1,4 @@ -package com.siyeh.igtest.jdk15.while_can_be_foreach; +package com.siyeh.igtest.migration.while_can_be_foreach; import java.util.*; diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/while_can_be_foreach/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/while_can_be_foreach/expected.xml similarity index 100% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/jdk15/while_can_be_foreach/expected.xml rename to plugins/InspectionGadgets/test/com/siyeh/igtest/migration/while_can_be_foreach/expected.xml diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspectionTest.java new file mode 100644 index 000000000000..d07664e4ef8b --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspectionTest.java @@ -0,0 +1,12 @@ +package com.siyeh.ig.controlflow; + +import com.IGInspectionTestCase; + +public class IfStatementWithIdenticalBranchesInspectionTest + extends IGInspectionTestCase { + + public void test() throws Exception { + doTest("com/siyeh/igtest/controlflow/if_statement_with_identical_branches", + new IfStatementWithIdenticalBranchesInspection()); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/ForCanBeForeachInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/ForCanBeForeachInspectionTest.java similarity index 57% rename from plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/ForCanBeForeachInspectionTest.java rename to plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/ForCanBeForeachInspectionTest.java index 7ac680a8c3b6..e68038fbc0a6 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/ForCanBeForeachInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/ForCanBeForeachInspectionTest.java @@ -1,4 +1,4 @@ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.IGInspectionTestCase; import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; @@ -6,6 +6,6 @@ import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; public class ForCanBeForeachInspectionTest extends IGInspectionTestCase { public void test() throws Exception { - doTest("com/siyeh/igtest/jdk15/foreach", new LocalInspectionToolWrapper(new ForCanBeForeachInspection()), "java 1.5"); + doTest("com/siyeh/igtest/migration/foreach", new LocalInspectionToolWrapper(new ForCanBeForeachInspection()), "java 1.5"); } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/UnnecessaryBoxingInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/UnnecessaryBoxingInspectionTest.java similarity index 68% rename from plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/UnnecessaryBoxingInspectionTest.java rename to plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/UnnecessaryBoxingInspectionTest.java index 06d88ec849d1..e3041773eb5f 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/UnnecessaryBoxingInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/UnnecessaryBoxingInspectionTest.java @@ -1,11 +1,11 @@ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.IGInspectionTestCase; public class UnnecessaryBoxingInspectionTest extends IGInspectionTestCase { public void test() throws Exception { - doTest("com/siyeh/igtest/jdk15/unnecessary_boxing", + doTest("com/siyeh/igtest/migration/unnecessary_boxing", new UnnecessaryBoxingInspection()); } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/UnnecessaryUnboxingInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/UnnecessaryUnboxingInspectionTest.java similarity index 68% rename from plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/UnnecessaryUnboxingInspectionTest.java rename to plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/UnnecessaryUnboxingInspectionTest.java index 185923eef5e0..7cffee7eec27 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/UnnecessaryUnboxingInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/UnnecessaryUnboxingInspectionTest.java @@ -1,11 +1,11 @@ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.IGInspectionTestCase; public class UnnecessaryUnboxingInspectionTest extends IGInspectionTestCase { public void test() throws Exception { - doTest("com/siyeh/igtest/jdk15/unnecessary_unboxing", + doTest("com/siyeh/igtest/migration/unnecessary_unboxing", new UnnecessaryUnboxingInspection()); } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/WhileCanBeForeachInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/WhileCanBeForeachInspectionTest.java similarity index 68% rename from plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/WhileCanBeForeachInspectionTest.java rename to plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/WhileCanBeForeachInspectionTest.java index e8c5959b9087..9352af5030ac 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/jdk15/WhileCanBeForeachInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/WhileCanBeForeachInspectionTest.java @@ -1,11 +1,11 @@ -package com.siyeh.ig.jdk15; +package com.siyeh.ig.migration; import com.IGInspectionTestCase; public class WhileCanBeForeachInspectionTest extends IGInspectionTestCase { public void test() throws Exception { - doTest("com/siyeh/igtest/jdk15/while_can_be_foreach", + doTest("com/siyeh/igtest/migration/while_can_be_foreach", new WhileCanBeForeachInspection()); } } diff --git a/plugins/IntentionPowerPak/src/META-INF/plugin.xml b/plugins/IntentionPowerPak/src/META-INF/plugin.xml index c1c1f3906840..67a5912a847c 100644 --- a/plugins/IntentionPowerPak/src/META-INF/plugin.xml +++ b/plugins/IntentionPowerPak/src/META-INF/plugin.xml @@ -336,6 +336,10 @@ com.siyeh.ipp.exceptions.ConvertCatchToThrowsIntention intention.category.other + + com.siyeh.ipp.exceptions.SplitMulticatchIntention + intention.category.other + com.siyeh.ipp.opassign.ReplaceWithOperatorAssignmentIntention intention.category.other diff --git a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties index efb61ee190fa..11e2cedffdc4 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties +++ b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties @@ -1,4 +1,4 @@ -plugin.IntentionPowerPack.description=Adds over 30 new intention actions for IDEA. +plugin.IntentionPowerPack.description=Adds over 80 new intention actions for IDEA. replace.fully.qualified.name.with.import.intention.name=Replace qualified name with 'import' replace.fully.qualified.name.with.import.intention.family.name=Replace Qualified Name with Import replace.if.with.switch.intention.name=Replace 'if' with 'switch' @@ -47,9 +47,9 @@ remove.unnecessary.parentheses.intention.name=Remove unnecessary parentheses remove.unnecessary.parentheses.intention.family.name=Remove Unnecessary Parentheses merge.if.and.intention.name=Merge nested 'if's merge.if.and.intention.family.name=Merge Nested Ifs to ANDed Condition -replace.concatenation.with.string.buffer.intention.name=Replace + with .append() +replace.concatenation.with.string.buffer.intention.name=Replace '+' with '.append()' replace.concatenation.with.string.buffer.intention.family.name=Replace + with StringBuffer.append() -remove.conditional.intention.name=Simplify ?: +remove.conditional.intention.name=Simplify '?:' remove.conditional.intention.family.name=Remove Pointless Conditional move.comment.to.separate.line.intention.name=Move comment to separate line move.comment.to.separate.line.intention.family.name=Move Comment to Separate Line @@ -79,7 +79,7 @@ replace.if.with.conditional.intention.name=Replace 'if else' with '?:' replace.if.with.conditional.intention.family.name=Replace If Else with Conditional replace.equality.with.equals.intention.name=Replace '==' with '.equals()' replace.equality.with.equals.intention.family.name=Replace Equality with Equals -make.append.chain.into.append.sequence.intention.name=Make .append() chain into .append() sequence +make.append.chain.into.append.sequence.intention.name=Make '.append()' chain into '.append()' sequence make.append.chain.into.append.sequence.intention.family.name=Make Append Chain Into Append Sequence detail.exceptions.intention.name=Detail exceptions detail.exceptions.intention.family.name=Detail Exceptions @@ -105,7 +105,7 @@ replace.multiply.with.shift.intention.family.name=Replace Multiply with Shift replace.with.operator.assignment.intention.family.name=Replace Assignment with Operator Assignment add.clarifying.parentheses.intention.name=Add clarifying parentheses add.clarifying.parentheses.intention.family.name=Add Clarifying Parentheses -convert.interface.to.class.intention.name=Convert to class +convert.interface.to.class.intention.name=Convert to 'class' convert.interface.to.class.intention.family.name=Convert Interface to Class replace.on.demand.import.intention.name=Replace with single class imports replace.on.demand.import.intention.family.name=Replace On Demand Import with Single Class Imports @@ -115,13 +115,13 @@ make.method.varargs.intention.family.name=Convert Method to Variable Argument Me convert.vararg.parameter.to.array.intention.name=Convert variable argument parameter to array convert.vararg.parameter.to.array.intention.family.name=Convert Variable Argument Parameter to Array Parameter replace.operator.assignment.with.assignment.intention.family.name=Replace Operator Assignment with Assignment -convert.catch.to.throws.intention.name=Replace catch section with throws declaration +convert.catch.to.throws.intention.name=Replace 'catch' section with 'throws' declaration convert.catch.to.throws.intention.family.name=Replace Catch Section with Throws Declaration wrap.vararg.arguments.with.explicit.array.intention.name=Wrap vararg arguments with explicit array creation wrap.vararg.arguments.with.explicit.array.intention.family.name=Wrap Vararg Arguments with Explicit Array Creation extract.while.loop.condition.to.if.statement.intention.name=Extract condition to internal 'if' statement extract.while.loop.condition.to.if.statement.intention.family.name=Extract While Loop Condition to Internal If Statement -replace.concatenation.with.format.string.intention.name=Replace '+ 'with 'String.format()' call +replace.concatenation.with.format.string.intention.name=Replace '+' with 'String.format()' call replace.concatenation.with.format.string.intention.family.name=Replace String Concatenation with String.format() Call copy.concatenated.string.to.clipboard.intention.name=Copy String concatenation text to the clipboard copy.concatenated.string.to.clipboard.intention.family.name=Copy String Concatenation Text to the Clipboard @@ -140,6 +140,8 @@ if.to.assertion.intention.family.name=Replace If with Assert Statement if.to.assertion.intention.name=Replace 'if' with 'assert' statement expand.to.normal.annotation.intention.family.name=Expand Annotation to Normal Form expand.to.normal.annotation.name=Expand to ''{0}'' +split.multicatch.intention.name=Split multicatch into separate 'catch' blocks +split.multicatch.intention.family.name=Split Multicatch into Separate Catch Blocks #hand made demorgans.intention.name1=Replace '\\&\\&' with '||' @@ -170,7 +172,7 @@ replace.operator.assignment.with.assignment.intention.name=Replace ''{0}'' with replace.some.operator.with.other.intention.name=Replace ''{0}'' with ''{1}'' swap.method.call.arguments.intention.name=Swap ''{0}'' and ''{1}'' flip.setter.call.intention.name=Flip Setter Call -adapter.to.listener.intention.name=Replace extension of ''{0}'' with Listener implementation +adapter.to.listener.intention.name=Replace extension of ''{0}'' with ''Listener'' implementation #categories intention.category.numbers=Numbers diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java index ca6aab3942ac..b02d21359914 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Bas Leijdekkers + * Copyright 2007-2011 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.siyeh.ipp.exceptions; +import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; @@ -22,22 +23,21 @@ import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; +import java.util.List; + public class ConvertCatchToThrowsIntention extends Intention { + @Override @NotNull protected PsiElementPredicate getElementPredicate() { return new ConvertCatchtoThrowsPredicate(); } + @Override protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException { final PsiCatchSection catchSection = (PsiCatchSection) element.getParent(); - final PsiType catchType = catchSection.getCatchType(); - if (!(catchType instanceof PsiClassType)) { - return; - } - final PsiClassType classType = (PsiClassType) catchType; final PsiMethod method = PsiTreeUtil.getParentOfType(catchSection, PsiMethod.class); if (method == null) { @@ -49,11 +49,32 @@ public class ConvertCatchToThrowsIntention extends Intention { // YY. Do you want to modify the base method?" // [Yes][No][Cancel] final PsiReferenceList throwsList = method.getThrowsList(); - final PsiManager manager = element.getManager(); - final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - final PsiJavaCodeReferenceElement referenceElement = - factory.createReferenceElementByType(classType); - throwsList.add(referenceElement); + final Project project = element.getProject(); + final PsiElementFactory factory = + JavaPsiFacade.getElementFactory(project); + final PsiType catchType = catchSection.getCatchType(); + if (catchType instanceof PsiClassType) { + final PsiClassType classType = (PsiClassType) catchType; + final PsiJavaCodeReferenceElement referenceElement = + factory.createReferenceElementByType(classType); + throwsList.add(referenceElement); + } else if (catchType instanceof PsiDisjunctionType) { + final PsiDisjunctionType disjunctionType = + (PsiDisjunctionType) catchType; + final List disjunctions = + disjunctionType.getDisjunctions(); + for (PsiType disjunction : disjunctions) { + if (!(disjunction instanceof PsiClassType)) { + continue; + } + final PsiClassType classType = (PsiClassType) disjunction; + final PsiJavaCodeReferenceElement referenceElement = + factory.createReferenceElementByType(classType); + throwsList.add(referenceElement); + } + } else { + return; + } final PsiTryStatement tryStatement = catchSection.getTryStatement(); final PsiCatchSection[] catchSections = tryStatement.getCatchSections(); if (catchSections.length > 1) { diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/MulticatchPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/MulticatchPredicate.java new file mode 100644 index 000000000000..eab4549f84d4 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/MulticatchPredicate.java @@ -0,0 +1,41 @@ +/* + * Copyright 2011 Bas Leijdekkers + * + * 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.siyeh.ipp.exceptions; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ipp.base.PsiElementPredicate; + +public class MulticatchPredicate implements PsiElementPredicate { + + public boolean satisfiedBy(PsiElement element) { + if (!(element instanceof PsiKeyword)) { + return false; + } + final PsiJavaToken javaToken = (PsiJavaToken) element; + final IElementType tokenType = javaToken.getTokenType(); + if (!tokenType.equals(JavaTokenType.CATCH_KEYWORD)) { + return false; + } + final PsiElement parent = javaToken.getParent(); + if (!(parent instanceof PsiCatchSection)) { + return false; + } + final PsiCatchSection catchSection = (PsiCatchSection) parent; + final PsiType type = catchSection.getCatchType(); + return type instanceof PsiDisjunctionType; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitMulticatchIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitMulticatchIntention.java new file mode 100644 index 000000000000..effb4f663b4b --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/SplitMulticatchIntention.java @@ -0,0 +1,72 @@ +/* + * Copyright 2011 Bas Leijdekkers + * + * 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.siyeh.ipp.exceptions; + +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.base.Intention; +import com.siyeh.ipp.base.PsiElementPredicate; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class SplitMulticatchIntention extends Intention { + + @NotNull + @Override + protected PsiElementPredicate getElementPredicate() { + return new MulticatchPredicate(); + } + + @Override + protected void processIntention(@NotNull PsiElement element) + throws IncorrectOperationException { + final PsiElement parent = element.getParent(); + if (!(parent instanceof PsiCatchSection)) { + return; + } + final PsiCatchSection catchSection = (PsiCatchSection) parent; + final PsiElement grandParent = catchSection.getParent(); + if (!(grandParent instanceof PsiTryStatement)) { + return; + } + final PsiParameter parameter = catchSection.getParameter(); + if (parameter == null) { + return; + } + final PsiType type = parameter.getType(); + if (!(type instanceof PsiDisjunctionType)) { + return; + } + final PsiDisjunctionType disjunctionType = (PsiDisjunctionType) type; + final List disjunctions = disjunctionType.getDisjunctions(); + final PsiElementFactory factory = + JavaPsiFacade.getElementFactory(element.getProject()); + for (PsiType disjunction : disjunctions) { + final PsiCatchSection copy = (PsiCatchSection) catchSection.copy(); + final PsiParameter copyParameter = copy.getParameter(); + if (copyParameter == null) { + continue; + } + final PsiTypeElement typeElement = copyParameter.getTypeElement(); + final PsiTypeElement newTypeElement = + factory.createTypeElement(disjunction); + typeElement.replace(newTypeElement); + grandParent.addBefore(copy, catchSection); + } + catchSection.delete(); + } +} diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/SplitMulticatchIntention/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/SplitMulticatchIntention/after.java.template new file mode 100644 index 000000000000..8a3ba03bb373 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/SplitMulticatchIntention/after.java.template @@ -0,0 +1,16 @@ +import java.io.IOException; +import java.net.*; + +public class X { + void f() { + try { + throw new NoRouteToHostException(); + } catch (NoRouteToHostException e) { + e.printStackTrace(); + } catch (SocketException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/SplitMulticatchIntention/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/SplitMulticatchIntention/before.java.template new file mode 100644 index 000000000000..8d08a5453a3b --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/SplitMulticatchIntention/before.java.template @@ -0,0 +1,12 @@ +import java.io.IOException; +import java.net.*; + +public class X { + void f() { + try { + throw new NoRouteToHostException(); + } catch (NoRouteToHostException | SocketException | IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/SplitMulticatchIntention/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/SplitMulticatchIntention/description.html new file mode 100644 index 000000000000..89419d184ee4 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/SplitMulticatchIntention/description.html @@ -0,0 +1,7 @@ + + +This intention splits a multicatch section into +separate catch blocks. + + + \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java index 1219f24a3904..a29c4f78abab 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java +++ b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java @@ -61,7 +61,8 @@ public class AndroidMavenExecutor { result.put(CompilerMessageCategory.ERROR, new ArrayList()); try { - JavaParameters javaParams = MavenExternalParameters.createJavaParameters(parameters, projectsManager.getGeneralSettings(), + JavaParameters javaParams = MavenExternalParameters.createJavaParameters(module.getProject(), parameters, + projectsManager.getGeneralSettings(), MavenRunner.getInstance(module.getProject()).getSettings()); GeneralCommandLine commandLine = CommandLineBuilder.createFromJavaParameters(javaParams); diff --git a/plugins/android/src/org/jetbrains/android/run/AndroidRunConfiguration.java b/plugins/android/src/org/jetbrains/android/run/AndroidRunConfiguration.java index 64dd0fc2cb42..5c8b414c6f0b 100644 --- a/plugins/android/src/org/jetbrains/android/run/AndroidRunConfiguration.java +++ b/plugins/android/src/org/jetbrains/android/run/AndroidRunConfiguration.java @@ -35,6 +35,7 @@ import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.search.ProjectScope; +import com.intellij.refactoring.listeners.RefactoringElementAdapter; import com.intellij.refactoring.listeners.RefactoringElementListener; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.facet.AndroidFacet; @@ -115,12 +116,8 @@ public class AndroidRunConfiguration extends AndroidRunConfigurationBase impleme @Nullable public RefactoringElementListener getRefactoringElementListener(PsiElement element) { if (element instanceof PsiClass && Comparing.strEqual(((PsiClass)element).getQualifiedName(), ACTIVITY_CLASS, true)) { - return new RefactoringElementListener() { - public void elementMoved(@NotNull PsiElement newElement) { - ACTIVITY_CLASS = ((PsiClass)newElement).getQualifiedName(); - } - - public void elementRenamed(@NotNull PsiElement newElement) { + return new RefactoringElementAdapter() { + public void elementRenamedOrMoved(@NotNull PsiElement newElement) { ACTIVITY_CLASS = ((PsiClass)newElement).getQualifiedName(); } }; diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java index cefc93e4dcfe..c20ac8d33c29 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java @@ -343,9 +343,9 @@ public class AntConfigurationImpl extends AntConfigurationBase implements Persis return null; } for (ExecutionEvent ev : events) { - final String presentableName = ev.getPresentableName(); - if (Comparing.strEqual(targetName, presentableName)) { - return new MetaTarget(buildFile, presentableName, ((ExecuteCompositeTargetEvent)ev).getTargetNames()); + final String name = ExecuteCompositeTargetEvent.TYPE_ID.equals(ev.getTypeId())? ((ExecuteCompositeTargetEvent)ev).getMetaTargetName() : ev.getPresentableName(); + if (Comparing.strEqual(targetName, name)) { + return new MetaTarget(buildFile, ev.getPresentableName(), ((ExecuteCompositeTargetEvent)ev).getTargetNames()); } } return null; diff --git a/plugins/devkit/src/dom/ExtensionPoint.java b/plugins/devkit/src/dom/ExtensionPoint.java index 658ca26ef55b..0f75c0b2bcca 100644 --- a/plugins/devkit/src/dom/ExtensionPoint.java +++ b/plugins/devkit/src/dom/ExtensionPoint.java @@ -23,6 +23,7 @@ import org.jetbrains.idea.devkit.dom.impl.PluginPsiClassConverter; /** * @author mike */ +@Presentation(typeName = "Extension Point") public interface ExtensionPoint extends DomElement { enum Area { IDEA_PROJECT, diff --git a/plugins/devkit/testData/codeInsight/extensionPointPresentation.xml b/plugins/devkit/testData/codeInsight/extensionPointPresentation.xml new file mode 100644 index 000000000000..62e15ab49569 --- /dev/null +++ b/plugins/devkit/testData/codeInsight/extensionPointPresentation.xml @@ -0,0 +1,14 @@ + + + foo + + + + + + + + ar/> + + + \ No newline at end of file diff --git a/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java b/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java index 27ba8b3ef621..b3b515a2e4a9 100644 --- a/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java +++ b/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java @@ -15,13 +15,19 @@ */ package org.jetbrains.idea.devkit.codeInsight; +import com.intellij.codeInsight.TargetElementUtil; +import com.intellij.codeInsight.TargetElementUtilBase; import com.intellij.openapi.application.PluginPathManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.psi.ElementDescriptionUtil; +import com.intellij.psi.PsiElement; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; import com.intellij.testFramework.fixtures.TempDirTestFixture; +import com.intellij.usageView.UsageViewNodeTextLocation; +import com.intellij.usageView.UsageViewTypeLocation; import org.jetbrains.idea.devkit.DevKitInspectionToolProvider; import java.io.IOException; @@ -136,4 +142,12 @@ public class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase { myFixture.testHighlighting("pluginWithXInclude.xml", "extensionPoints.xml"); } + public void testExtensionPointPresentation() { + myFixture.configureByFile(getTestName(true) + ".xml"); + final PsiElement element = + TargetElementUtil.findTargetElement(myFixture.getEditor(), TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED); + assertEquals("Extension Point", ElementDescriptionUtil.getElementDescription(element, UsageViewTypeLocation.INSTANCE)); + assertEquals("Extension Point bar", ElementDescriptionUtil.getElementDescription(element, UsageViewNodeTextLocation.INSTANCE)); + } + } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/generate/constructors/GroovyGenerationInfo.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/generate/constructors/GroovyGenerationInfo.java index 87929cbb6865..6e36d660ffe5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/generate/constructors/GroovyGenerationInfo.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/generate/constructors/GroovyGenerationInfo.java @@ -61,7 +61,7 @@ public class GroovyGenerationInfo extends PsiGenerationInfo } final IElementType type = element.getNode().getElementType(); - if (GroovyTokenTypes.WHITE_SPACES_SET.contains(type)) { + if (type == GroovyTokenTypes.mNLS || type == GroovyTokenTypes.mWS) { return element.getNextSibling(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java index 172e0c27d508..eceac6bbfec4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java @@ -16,9 +16,11 @@ package org.jetbrains.plugins.groovy.codeInspection.utils; import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; @@ -34,6 +36,9 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnState import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrPostfixExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ControlFlowBuilder; @@ -482,6 +487,17 @@ public class ControlFlowUtils { return null; } + public static boolean isIncOrDecOperand(GrReferenceExpression referenceExpression) { + final PsiElement parent = referenceExpression.getParent(); + if (parent instanceof GrPostfixExpression) return true; + if (parent instanceof GrUnaryExpression) { + final IElementType opType = ((GrUnaryExpression)parent).getOperationTokenType(); + return opType == GroovyElementTypes.mDEC || opType == GroovyElementTypes.mINC; + } + + return false; + } + private static class ReturnFinder extends GroovyRecursiveElementVisitor { private boolean m_found = false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java index 9b9ee11ec62d..3a372ce2cbd8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java @@ -26,12 +26,26 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.tree.CompositeElement; import com.intellij.psi.tree.IElementType; -import static org.jetbrains.plugins.groovy.GroovyFileType.GROOVY_LANGUAGE; import org.jetbrains.plugins.groovy.formatter.GroovyBlock; import org.jetbrains.plugins.groovy.lang.editor.actions.GroovyEditorActionUtil; +import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.*; +import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementVisitor; +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; + +import static org.jetbrains.plugins.groovy.GroovyFileType.GROOVY_LANGUAGE; import static org.jetbrains.plugins.groovy.lang.groovydoc.lexer.GroovyDocTokenTypes.mGDOC_TAG_VALUE_COMMA; import static org.jetbrains.plugins.groovy.lang.groovydoc.lexer.GroovyDocTokenTypes.mGDOC_TAG_VALUE_LPAREN; -import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.*; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.COMMENT_SET; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.kELSE; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.kNEW; @@ -52,19 +66,6 @@ import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.mGDOC_ import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.mGDOC_TAG_VALUE_RPAREN; import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.mNLS; import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.mRCURLY; -import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementVisitor; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; /** * @author ilyas @@ -263,7 +264,7 @@ public class GroovySpacingProcessor extends GroovyPsiElementVisitor { createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_PARENTHESES); } else if (myChild2.getElementType() == mRPAREN && myChild2.getElementType() == THROW_CLAUSE) { createSpaceInCode(true); - } else if (myChild2.getElementType() == OPEN_BLOCK) { + } else if (isOpenBlock(myChild2)) { PsiElement methodName = method.getNameIdentifier(); int dependancyStart = methodName == null ? myParent.getTextRange().getStartOffset() : methodName.getTextRange().getStartOffset(); myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_METHOD_LBRACE, mySettings.METHOD_BRACE_STYLE, @@ -277,6 +278,10 @@ public class GroovySpacingProcessor extends GroovyPsiElementVisitor { } + private static boolean isOpenBlock(final ASTNode node) { + return node.getElementType() == OPEN_BLOCK || node.getElementType() == CONSTRUCTOR_BODY; + } + public void visitDocMethodReference(GrDocMethodReference reference) { visitDocMember(); } @@ -322,14 +327,14 @@ public class GroovySpacingProcessor extends GroovyPsiElementVisitor { } public void visitCatchClause(GrCatchClause catchClause) { - if (myChild2.getElementType() == OPEN_BLOCK) { + if (isOpenBlock(myChild2)) { myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_TRY_LBRACE, mySettings.BRACE_STYLE, null, mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); } } public void visitFinallyClause(GrFinallyClause catchClause) { - if (myChild2.getElementType() == OPEN_BLOCK) { + if (isOpenBlock(myChild2)) { myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_TRY_LBRACE, mySettings.BRACE_STYLE, null, mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); } @@ -338,7 +343,7 @@ public class GroovySpacingProcessor extends GroovyPsiElementVisitor { public void visitTryStatement(GrTryCatchStatement tryCatchStatement) { if (myChild2.getElementType() == FINALLY_CLAUSE) { processOnNewLineCondition(mySettings.FINALLY_ON_NEW_LINE); - } else if (myChild2.getElementType() == OPEN_BLOCK) { + } else if (isOpenBlock(myChild2)) { myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_TRY_LBRACE, mySettings.BRACE_STYLE, null, mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); } else if (myChild2.getElementType() == CATCH_CLAUSE) { @@ -362,7 +367,7 @@ public class GroovySpacingProcessor extends GroovyPsiElementVisitor { createSpaceInCode(mySettings.SPACE_BEFORE_SYNCHRONIZED_PARENTHESES); } else if (myChild1.getElementType() == mLPAREN || myChild2.getElementType() == mRPAREN) { createSpaceInCode(mySettings.SPACE_WITHIN_SYNCHRONIZED_PARENTHESES); - } else if (myChild2.getElementType() == OPEN_BLOCK) { + } else if (isOpenBlock(myChild2)) { myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_SYNCHRONIZED_LBRACE, mySettings.BRACE_STYLE, null, mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); @@ -390,7 +395,7 @@ public class GroovySpacingProcessor extends GroovyPsiElementVisitor { public void visitIfStatement(GrIfStatement ifStatement) { if (myChild2.getElementType() == kELSE) { - if (myChild1.getElementType() != OPEN_BLOCK && myChild1.getElementType() != BLOCK_STATEMENT) { + if (!isOpenBlock(myChild1) && myChild1.getElementType() != BLOCK_STATEMENT) { myResult = Spacing.createSpacing(1, 1, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); } else { if (mySettings.ELSE_ON_NEW_LINE) { @@ -407,7 +412,7 @@ public class GroovySpacingProcessor extends GroovyPsiElementVisitor { myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); } } else { - if (myChild2.getElementType() == BLOCK_STATEMENT || myChild2.getElementType() == OPEN_BLOCK) { + if (myChild2.getElementType() == BLOCK_STATEMENT || isOpenBlock(myChild2)) { myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_ELSE_LBRACE, mySettings.BRACE_STYLE, null, mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); @@ -415,7 +420,7 @@ public class GroovySpacingProcessor extends GroovyPsiElementVisitor { createSpacingBeforeElementInsideControlStatement(); } } - } else if (myChild2.getElementType() == BLOCK_STATEMENT || myChild2.getElementType() == OPEN_BLOCK) { + } else if (myChild2.getElementType() == BLOCK_STATEMENT || isOpenBlock(myChild2)) { boolean space = myChild2.getPsi() == ((GrIfStatement) myParent).getElseBranch() ? mySettings.SPACE_BEFORE_ELSE_LBRACE : mySettings.SPACE_BEFORE_IF_LBRACE; myResult = getSpaceBeforeLBrace(space, mySettings.BRACE_STYLE, new TextRange(myParent.getTextRange().getStartOffset(), myChild1.getTextRange().getEndOffset()), @@ -451,7 +456,7 @@ public class GroovySpacingProcessor extends GroovyPsiElementVisitor { new TextRange(lparenth.getTextRange().getStartOffset(), myChild2.getTextRange().getEndOffset())); } - } else if (myChild2.getElementType() == BLOCK_STATEMENT || myChild2.getElementType() == OPEN_BLOCK) { + } else if (myChild2.getElementType() == BLOCK_STATEMENT || isOpenBlock(myChild2)) { if (myChild2.getElementType() == BLOCK_STATEMENT) { myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_FOR_LBRACE, mySettings.BRACE_STYLE, new TextRange(myParent.getTextRange().getStartOffset(), myChild1.getTextRange().getEndOffset()), mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java index 7551466bd588..e3b30d2c250d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java @@ -254,7 +254,7 @@ public class GroovyFoldingBuilder implements FoldingBuilder, GroovyElementTypes, return settings.isCollapseJavadocs(); } - if (node.getElementType() == OPEN_BLOCK && node.getTreeParent().getElementType() == METHOD_DEFINITION) { + if ((node.getElementType() == OPEN_BLOCK || node.getElementType() == CONSTRUCTOR_BODY) && node.getTreeParent().getElementType() == METHOD_DEFINITION) { return settings.isCollapseMethods(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/groovydoc/psi/impl/GrDocTagImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/groovydoc/psi/impl/GrDocTagImpl.java index 420dde38b7b5..1314771b563d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/groovydoc/psi/impl/GrDocTagImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/groovydoc/psi/impl/GrDocTagImpl.java @@ -99,8 +99,4 @@ public class GrDocTagImpl extends GroovyDocPsiElementImpl implements GrDocTag { return this; } - @Override - public void delete() throws IncorrectOperationException { - getParent().deleteChildRange(this, this); - } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GrCodeBlockElementType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GrCodeBlockElementType.java new file mode 100644 index 000000000000..9ffb906c353e --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GrCodeBlockElementType.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.parser; + +import com.intellij.lang.ASTNode; +import com.intellij.lexer.Lexer; +import com.intellij.openapi.project.Project; +import com.intellij.psi.tree.ICompositeElementType; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.IErrorCounterReparseableElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.GroovyFileType; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyLexer; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrBlockImpl; + +/** + * @author peter + */ +public abstract class GrCodeBlockElementType extends IErrorCounterReparseableElementType implements ICompositeElementType { + + protected GrCodeBlockElementType(String debugName) { + super(debugName, GroovyFileType.GROOVY_LANGUAGE); + } + + @NotNull + @Override + public ASTNode createCompositeNode() { + return createNode(null); + } + + @Override + @NotNull + public abstract GrBlockImpl createNode(final CharSequence text); + + @Override + public int getErrorsCount(final CharSequence seq, final Project project) { + final Lexer lexer = new GroovyLexer(); + + lexer.start(seq); + if (lexer.getTokenType() != GroovyTokenTypes.mLCURLY) return FATAL_ERROR; + lexer.advance(); + int balance = 1; + while (true) { + IElementType type = lexer.getTokenType(); + if (type == null) break; + if (balance == 0) return FATAL_ERROR; + if (type == GroovyTokenTypes.mLCURLY) { + balance++; + } + else if (type == GroovyTokenTypes.mRCURLY) { + balance--; + } + lexer.advance(); + } + return balance; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java index 3d6b5fae30e2..4e9463950056 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java @@ -21,6 +21,7 @@ import com.intellij.psi.stubs.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.util.io.StringRef; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.lang.groovydoc.parser.GroovyDocElementTypes; import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType; @@ -38,6 +39,9 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameter; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList; import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.GrVariableDeclarationBase; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrBlockImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrClosableBlockImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrOpenBlockImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.params.GrParameterImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.params.GrParameterListImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.*; @@ -140,8 +144,27 @@ public interface GroovyElementTypes extends GroovyTokenTypes, GroovyDocElementTy //Packaging GroovyElementType PACKAGE_DEFINITION = new GroovyElementType("Package definition"); - GroovyElementType CLOSABLE_BLOCK = new GroovyElementType("Closable block"); - GroovyElementType OPEN_BLOCK = new GroovyElementType("Open block"); + GrCodeBlockElementType CLOSABLE_BLOCK = new GrCodeBlockElementType("Closable block") { + @NotNull + @Override + public GrBlockImpl createNode(CharSequence text) { + return new GrClosableBlockImpl(this, text); + } + }; + GrCodeBlockElementType OPEN_BLOCK = new GrCodeBlockElementType("Open block") { + @NotNull + @Override + public GrBlockImpl createNode(CharSequence text) { + return new GrOpenBlockImpl(this, text); + } + }; + GrCodeBlockElementType CONSTRUCTOR_BODY = new GrCodeBlockElementType("Constructor body") { + @NotNull + @Override + public GrBlockImpl createNode(CharSequence text) { + return new GrOpenBlockImpl(this, text); + } + }; GroovyElementType BLOCK_STATEMENT = new GroovyElementType("Block statement"); @@ -394,6 +417,7 @@ public interface GroovyElementTypes extends GroovyTokenTypes, GroovyDocElementTy TokenSet BLOCK_SET = TokenSet.create(CLOSABLE_BLOCK, BLOCK_STATEMENT, + CONSTRUCTOR_BODY, OPEN_BLOCK, ENUM_BODY, CLASS_BODY); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyParser.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyParser.java index 7d2d8ad5fa60..df1ee5cccb10 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyParser.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyParser.java @@ -26,6 +26,7 @@ import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.parser.parsing.auxiliary.Separators; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.*; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.blocks.OpenOrClosableBlock; +import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.constructor.ConstructorBody; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.declaration.Declaration; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.AssignmentExpression; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.ConditionalExpression; @@ -42,14 +43,29 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; */ public class GroovyParser implements PsiParser { + public boolean parseDeep() { + return false; + } + @NotNull public ASTNode parse(IElementType root, PsiBuilder builder) { //builder.setDebugMode(true); - PsiBuilder.Marker rootMarker = builder.mark(); - CompilationUnit.parse(builder, this); - rootMarker.done(root); + if (root == GroovyElementTypes.OPEN_BLOCK) { + OpenOrClosableBlock.parseOpenBlockDeep(builder, this); + } + else if (root == GroovyElementTypes.CLOSABLE_BLOCK) { + OpenOrClosableBlock.parseClosableBlockDeep(builder, this); + } + else if (root == GroovyElementTypes.CONSTRUCTOR_BODY) { + ConstructorBody.parseConstructorBodyDeep(builder, this); + } + else { + assert root == GroovyParserDefinition.GROOVY_FILE : root; + PsiBuilder.Marker rootMarker = builder.mark(); + CompilationUnit.parseFile(builder, this); + rootMarker.done(root); + } return builder.getTreeBuilt(); - } public boolean parseForStatement(PsiBuilder builder) { @@ -240,7 +256,7 @@ public class GroovyParser implements PsiParser { result = parseStatement(builder, false); if (!isExtendedSeparator(builder.getTokenType())) { - cleanAfterError(builder); + cleanAfterError(builder, false); } } Separators.parse(builder); @@ -301,18 +317,33 @@ public class GroovyParser implements PsiParser { /** * Rolls marker forward after possible errors - * - * @param builder */ - protected void cleanAfterError(PsiBuilder builder) { + private void cleanAfterError(PsiBuilder builder, boolean rCurlyNeeded) { + int braceLevel = 1; int i = 0; PsiBuilder.Marker em = builder.mark(); - while (!builder.eof() && - !(GroovyTokenTypes.mNLS.equals(builder.getTokenType()) || - GroovyTokenTypes.mRCURLY.equals(builder.getTokenType()) || - GroovyTokenTypes.mSEMI.equals(builder.getTokenType())) && - !isExtendedSeparator(builder.getTokenType()) - ) { + while (true) { + if (builder.eof()) { + break; + } + final IElementType type = builder.getTokenType(); + if (GroovyTokenTypes.mLCURLY == type) { + braceLevel++; + } + else if (GroovyTokenTypes.mRCURLY == type) { + braceLevel--; + if (braceLevel == 0) { + break; + } + } + else if (braceLevel == 1) { + if (!rCurlyNeeded && (GroovyTokenTypes.mNLS.equals(type) || GroovyTokenTypes.mSEMI.equals(type))) { + break; + } + if (isExtendedSeparator(type)) { + break; + } + } builder.advanceLexer(); i++; } @@ -345,10 +376,10 @@ public class GroovyParser implements PsiParser { } result = parseStatement(builder, false); if (!isExtendedSeparator(builder.getTokenType())) { - cleanAfterError(builder); + cleanAfterError(builder, false); } } - cleanAfterError(builder); + cleanAfterError(builder, true); Separators.parse(builder); while (parseExtendedStatement(builder)) { Separators.parse(builder); @@ -358,7 +389,10 @@ public class GroovyParser implements PsiParser { public boolean parseStatement(PsiBuilder builder, boolean isBlockStatementNeeded) { if (isBlockStatementNeeded && GroovyTokenTypes.mLCURLY.equals(builder.getTokenType())) { - return OpenOrClosableBlock.parseBlockStatement(builder, this); + final PsiBuilder.Marker marker = builder.mark(); + OpenOrClosableBlock.parseOpenBlockDeep(builder, this); + marker.done(GroovyElementTypes.BLOCK_STATEMENT); + return true; } if (GroovyTokenTypes.kIMPORT.equals(builder.getTokenType())) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java index 1a9a1f8009e0..3145b5f202b5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java @@ -33,8 +33,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.*; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.arguments.GrArgumentLabelImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.arguments.GrArgumentListImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.arguments.GrNamedArgumentImpl; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrClosableBlockImpl; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrOpenBlockImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.branch.*; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.clauses.GrCaseLabelImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.clauses.GrCaseSectionImpl; @@ -66,7 +64,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.types.G import org.jetbrains.plugins.groovy.lang.psi.impl.statements.params.GrParameterImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.params.GrParameterListImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.*; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.GrTypeDefinitionBodyBase; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.enumConstant.GrEnumConstantImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.enumConstant.GrEnumConstantListImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.members.GrAnnotationMethodImpl; @@ -169,8 +166,6 @@ public class GroovyPsiCreator implements GroovyElementTypes { //bodies if (elem.equals(CLASS_BODY)) return new GrTypeDefinitionBodyBase.GrClassBody(node); if (elem.equals(ENUM_BODY)) return new GrTypeDefinitionBodyBase.GrEnumBody(node); - if (elem.equals(CLOSABLE_BLOCK)) return new GrClosableBlockImpl(node); - if (elem.equals(OPEN_BLOCK)) return new GrOpenBlockImpl(node); if (elem.equals(BLOCK_STATEMENT)) return new GrBlockStatementImpl(node); if (elem.equals(EXPLICIT_CONSTRUCTOR)) return new GrConstructorInvocationImpl(node); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/blocks/OpenOrClosableBlock.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/blocks/OpenOrClosableBlock.java index 5ee50f4c79e4..11fbd687fbd4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/blocks/OpenOrClosableBlock.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/blocks/OpenOrClosableBlock.java @@ -17,8 +17,8 @@ package org.jetbrains.plugins.groovy.lang.parser.parsing.statements.blocks; import com.intellij.lang.PsiBuilder; +import com.intellij.psi.tree.IElementType; import org.jetbrains.plugins.groovy.GroovyBundle; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.parser.GroovyParser; import org.jetbrains.plugins.groovy.lang.parser.parsing.auxiliary.parameters.ParameterList; @@ -29,77 +29,76 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; */ public class OpenOrClosableBlock implements GroovyElementTypes { - - /** - * Parses open block as block, not as statement - * - * @param builder - * @return - */ public static boolean parseOpenBlock(PsiBuilder builder, GroovyParser parser) { - return parseOpenBlockInDifferentContext(builder, false, parser); - } - - /** - * Parses open block as a usual statement in role of loop or fork statement body - * - * @param builder - * @return - */ - public static boolean parseBlockStatement(PsiBuilder builder, GroovyParser parser) { - return parseOpenBlockInDifferentContext(builder, true, parser); - } - - /** - * Parses only OPEN blocks - * - * @param builder - * @return - */ - public static boolean parseOpenBlockInDifferentContext(PsiBuilder builder, boolean isBlockStatement, GroovyParser parser) { - PsiBuilder.Marker blockStatementMarker = builder.mark(); - PsiBuilder.Marker marker = builder.mark(); - if (!ParserUtils.getToken(builder, mLCURLY)) { - marker.drop(); - blockStatementMarker.drop(); + if (builder.getTokenType() != mLCURLY) { return false; } + + if (parser.parseDeep()) { + parseOpenBlockDeep(builder, parser); + } else { + parseBlockShallow(builder, OPEN_BLOCK); + } + + return true; + } + + public static void parseOpenBlockDeep(PsiBuilder builder, GroovyParser parser) { + PsiBuilder.Marker marker = builder.mark(); + builder.advanceLexer(); ParserUtils.getToken(builder, mNLS); parser.parseBlockBody(builder); while (!builder.eof() && - !mRCURLY.equals(builder.getTokenType())) { + !mRCURLY.equals(builder.getTokenType())) { builder.error(GroovyBundle.message("expression.expected")); builder.advanceLexer(); } ParserUtils.getToken(builder, mRCURLY, GroovyBundle.message("rcurly.expected")); marker.done(OPEN_BLOCK); - if (isBlockStatement) { - blockStatementMarker.done(BLOCK_STATEMENT); - } else { - blockStatementMarker.drop(); - } - return true; } - /** - * Parses CLOSABLE blocks - * - * @param builder - * @return - */ - public static GroovyElementType parseClosableBlock(PsiBuilder builder, GroovyParser parser) { - PsiBuilder.Marker marker = builder.mark(); - if (!ParserUtils.getToken(builder, mLCURLY)) { - marker.drop(); - return WRONGWAY; + public static IElementType parseClosableBlock(PsiBuilder builder, GroovyParser parser) { + assert builder.getTokenType() == mLCURLY : builder.getTokenType(); + if (parser.parseDeep()) { + parseClosableBlockDeep(builder, parser); + } else { + parseBlockShallow(builder, CLOSABLE_BLOCK); } + return CLOSABLE_BLOCK; + } + + public static void parseBlockShallow(PsiBuilder builder, IElementType blockType) { + final PsiBuilder.Marker blockStart = builder.mark(); + int braceCount = 0; + while (true) { + final IElementType tokenType = builder.getTokenType(); + if (tokenType == null) { + break; + } + + if (tokenType == mLCURLY) { + braceCount++; + } else if (tokenType == mRCURLY) { + braceCount--; + } + builder.advanceLexer(); + if (braceCount == 0) { + break; + } + } + blockStart.collapse(blockType); + } + + public static void parseClosableBlockDeep(PsiBuilder builder, GroovyParser parser) { + assert builder.getTokenType() == mLCURLY : builder.getTokenType(); + PsiBuilder.Marker marker = builder.mark(); + builder.advanceLexer(); ParserUtils.getToken(builder, mNLS); closableBlockParamsOpt(builder, parser); parser.parseBlockBody(builder); ParserUtils.getToken(builder, mRCURLY, GroovyBundle.message("rcurly.expected")); marker.done(CLOSABLE_BLOCK); - return CLOSABLE_BLOCK; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/constructor/ConstructorBody.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/constructor/ConstructorBody.java index a6ff89d69721..9f4e5424c050 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/constructor/ConstructorBody.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/constructor/ConstructorBody.java @@ -21,6 +21,7 @@ import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.parser.GroovyParser; import org.jetbrains.plugins.groovy.lang.parser.parsing.auxiliary.Separators; +import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.blocks.OpenOrClosableBlock; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.arguments.ArgumentList; import org.jetbrains.plugins.groovy.lang.parser.parsing.types.TypeArguments; import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; @@ -30,22 +31,26 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; * @date: 26.03.2007 */ public class ConstructorBody implements GroovyElementTypes { - public static boolean parse(PsiBuilder builder, GroovyParser parser) { - PsiBuilder.Marker cbMarker = builder.mark(); - - if (!ParserUtils.getToken(builder, mLCURLY)) { - builder.error(GroovyBundle.message("lcurly.expected")); - cbMarker.rollbackTo(); - return false; + public static void parseConstructorBody(PsiBuilder builder, GroovyParser parser) { + assert builder.getTokenType() == mLCURLY; + if (parser.parseDeep()) { + parseConstructorBodyDeep(builder, parser); + } else { + OpenOrClosableBlock.parseBlockShallow(builder, CONSTRUCTOR_BODY); } + } + public static void parseConstructorBodyDeep(PsiBuilder builder, GroovyParser parser) { + assert builder.getTokenType() == mLCURLY; + PsiBuilder.Marker cbMarker = builder.mark(); + builder.advanceLexer(); ParserUtils.getToken(builder, mNLS); - PsiBuilder.Marker constructorInvokationMarker = builder.mark(); + PsiBuilder.Marker constructorInvocationMarker = builder.mark(); if (parseExplicitConstructor(builder, parser)) { - constructorInvokationMarker.done(EXPLICIT_CONSTRUCTOR); + constructorInvocationMarker.done(EXPLICIT_CONSTRUCTOR); } else { - constructorInvokationMarker.rollbackTo(); + constructorInvocationMarker.rollbackTo(); } //explicit constructor invocation @@ -58,9 +63,7 @@ public class ConstructorBody implements GroovyElementTypes { builder.advanceLexer(); } - cbMarker.done(OPEN_BLOCK); - return true; - + cbMarker.done(CONSTRUCTOR_BODY); } private static boolean parseExplicitConstructor(PsiBuilder builder, GroovyParser parser) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arguments/ArgumentList.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arguments/ArgumentList.java index 3a890a245b86..1b68e4cc65c0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arguments/ArgumentList.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arguments/ArgumentList.java @@ -142,7 +142,7 @@ public class ArgumentList implements GroovyElementTypes { mLBRACK.equals(builder.getTokenType()) || mLPAREN.equals(builder.getTokenType()) || mLCURLY.equals(builder.getTokenType())) { - PrimaryExpression.parse(builder, parser); + PrimaryExpression.parsePrimaryExpression(builder, parser); if (mCOLON.equals(builder.getTokenType())) { marker.done(ARGUMENT_LABEL); return true; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java index a76f1fc45865..14ed00ae2153 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java @@ -46,7 +46,7 @@ public class PathExpression implements GroovyElementTypes { public static Result parseForExprStatement(PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker marker = builder.mark(); - final GroovyElementType qualifierType = PrimaryExpression.parse(builder, parser); + final IElementType qualifierType = PrimaryExpression.parsePrimaryExpression(builder, parser); if (qualifierType != WRONGWAY) { Result result = OK; if (isPathElementStart(builder)) { @@ -84,7 +84,7 @@ public class PathExpression implements GroovyElementTypes { private static Result pathElementParse(PsiBuilder builder, PsiBuilder.Marker marker, GroovyParser parser, - GroovyElementType qualifierType, + IElementType qualifierType, Result result) { GroovyElementType res; @@ -174,7 +174,7 @@ public class PathExpression implements GroovyElementTypes { !ParserUtils.lookAhead(builder, mLBRACK, mNLS, mCOLON); } - private static GroovyElementType parseThisSuperExpression(PsiBuilder builder, GroovyElementType qualifierType) { + private static GroovyElementType parseThisSuperExpression(PsiBuilder builder, IElementType qualifierType) { if (qualifierType != REFERENCE_EXPRESSION) { return WRONGWAY; } @@ -266,7 +266,7 @@ public class PathExpression implements GroovyElementTypes { * @param builder * @return */ - private static GroovyElementType appendedBlockParse(PsiBuilder builder, GroovyParser parser) { + private static IElementType appendedBlockParse(PsiBuilder builder, GroovyParser parser) { return OpenOrClosableBlock.parseClosableBlock(builder, parser); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java index 1b1671213904..c34a180f5ee9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java @@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.primary; import com.intellij.lang.PsiBuilder; +import com.intellij.psi.tree.IElementType; import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; @@ -35,7 +36,7 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; */ public class PrimaryExpression implements GroovyElementTypes { - public static GroovyElementType parse(PsiBuilder builder, GroovyParser parser) { + public static IElementType parsePrimaryExpression(PsiBuilder builder, GroovyParser parser) { if (TokenSets.BUILT_IN_TYPE.contains(builder.getTokenType())) { ParserUtils.eatElement(builder, BUILT_IN_TYPE_EXPRESSION); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ConstructorDefinition.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ConstructorDefinition.java index 7326ad1d10ce..1e4b1d45464a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ConstructorDefinition.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ConstructorDefinition.java @@ -69,10 +69,9 @@ public class ConstructorDefinition implements GroovyElementTypes { if (builder.getTokenType() == mLCURLY || ParserUtils.lookAhead(builder, mNLS, mLCURLY)) { ParserUtils.getToken(builder, mNLS); - if (ConstructorBody.parse(builder, parser)) { - constructorMarker.done(CONSTRUCTOR_DEFINITION); - return true; - } + ConstructorBody.parseConstructorBody(builder, parser); + constructorMarker.done(CONSTRUCTOR_DEFINITION); + return true; } constructorMarker.rollbackTo(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/toplevel/CompilationUnit.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/toplevel/CompilationUnit.java index c24deddfcef2..9220937d26d5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/toplevel/CompilationUnit.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/toplevel/CompilationUnit.java @@ -31,7 +31,7 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; */ public class CompilationUnit implements GroovyElementTypes { - public static void parse(PsiBuilder builder, GroovyParser parser) { + public static void parseFile(PsiBuilder builder, GroovyParser parser) { ParserUtils.getToken(builder, mSH_COMMENT); ParserUtils.getToken(builder, mNLS); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java index f9de874dc658..89f3c13880e1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java @@ -21,9 +21,9 @@ import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiConstantEvaluationHelper; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; -import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; @@ -359,7 +359,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { public void visitReferenceExpression(GrReferenceExpression referenceExpression) { super.visitReferenceExpression(referenceExpression); if (referenceExpression.getQualifierExpression() == null) { - if (isIncOrDecOperand(referenceExpression) && !myAssertionsOnly) { + if (ControlFlowUtils.isIncOrDecOperand(referenceExpression) && !myAssertionsOnly) { final ReadWriteVariableInstructionImpl i = new ReadWriteVariableInstructionImpl(referenceExpression, myInstructionNumber++, false); addNode(i); addNode(new ReadWriteVariableInstructionImpl(referenceExpression, myInstructionNumber++, true)); @@ -377,17 +377,6 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { } } - private static boolean isIncOrDecOperand(GrReferenceExpression referenceExpression) { - final PsiElement parent = referenceExpression.getParent(); - if (parent instanceof GrPostfixExpression) return true; - if (parent instanceof GrUnaryExpression) { - final IElementType opType = ((GrUnaryExpression)parent).getOperationTokenType(); - return opType == GroovyElementTypes.mDEC || opType == GroovyElementTypes.mINC; - } - - return false; - } - public void visitIfStatement(GrIfStatement ifStatement) { InstructionImpl ifInstruction = startNode(ifStatement); final GrCondition condition = ifStatement.getCondition(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrStubElementBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrStubElementBase.java index 7cee964ebee1..ba2f060fd114 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrStubElementBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrStubElementBase.java @@ -20,6 +20,7 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.stubs.StubElement; +import com.intellij.util.IncorrectOperationException; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; @@ -38,6 +39,11 @@ public abstract class GrStubElementBase extends StubBased super(node); } + @Override + public void delete() throws IncorrectOperationException { + getParent().deleteChildRange(this, this); + } + @Override public abstract PsiElement getParent(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementImpl.java index 1e5137d9a5f1..eb2e1dcb30b3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementImpl.java @@ -16,10 +16,12 @@ package org.jetbrains.plugins.groovy.lang.psi.impl; +import com.intellij.extapi.psi.ASTDelegatePsiElement; import com.intellij.extapi.psi.ASTWrapperPsiElement; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiInvalidElementAccessException; +import com.intellij.psi.impl.CheckUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; @@ -36,6 +38,16 @@ public abstract class GroovyPsiElementImpl extends ASTWrapperPsiElement implemen super(node); } + @Override + public void delete() throws IncorrectOperationException { + if (getParent() instanceof ASTDelegatePsiElement) { + CheckUtil.checkWritable(this); + ((ASTDelegatePsiElement) getParent()).deleteChildInternal(getNode()); + } else { + getParent().deleteChildRange(this, this); + } + } + public void accept(GroovyElementVisitor visitor) { visitor.visitElement(this); } @@ -56,7 +68,11 @@ public abstract class GroovyPsiElementImpl extends ASTWrapperPsiElement implemen } public void removeElements(PsiElement[] elements) throws IncorrectOperationException { - ASTNode parentNode = getNode(); + removeElements(this, elements); + } + + public static void removeElements(PsiElement from, PsiElement[] elements) { + ASTNode parentNode = from.getNode(); for (PsiElement element : elements) { if (element.isValid()) { ASTNode node = element.getNode(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrBlockImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrBlockImpl.java index afcf88116536..dfd3f5412c42 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrBlockImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrBlockImpl.java @@ -20,8 +20,10 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.ResolveState; import com.intellij.psi.impl.source.tree.Factory; +import com.intellij.psi.impl.source.tree.LazyParseablePsiElement; import com.intellij.psi.impl.source.tree.LeafElement; import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; @@ -30,6 +32,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; +import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; @@ -45,9 +48,31 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; /** * @author ven */ -public abstract class GrBlockImpl extends GroovyPsiElementImpl implements GrCodeBlock, GrControlFlowOwner { +public abstract class GrBlockImpl extends LazyParseablePsiElement implements GrCodeBlock, GrControlFlowOwner { private volatile CachedValue myControlFlow = null; + protected GrBlockImpl(@NotNull IElementType type, CharSequence buffer) { + super(type, buffer); + } + + @Override + public void removeElements(PsiElement[] elements) throws IncorrectOperationException { + GroovyPsiElementImpl.removeElements(this, elements); + } + + @Override + public void acceptChildren(GroovyElementVisitor visitor) { + GroovyPsiElementImpl.acceptGroovyChildren(this, visitor); + } + + public T replaceWithStatement(T statement) { + return GroovyPsiElementImpl.replaceWithStatement(this, statement); + } + + public void removeStatement() throws IncorrectOperationException { + GroovyPsiElementImpl.removeStatement(this); + } + public void subtreeChanged() { super.subtreeChanged(); myControlFlow = null; @@ -84,10 +109,6 @@ public abstract class GrBlockImpl extends GroovyPsiElementImpl implements GrCode return controlFlow.getValue(); } - public GrBlockImpl(@NotNull ASTNode node) { - super(node); - } - public void removeVariable(GrVariable variable) { PsiImplUtil.removeVariable(variable); } @@ -153,12 +174,12 @@ public abstract class GrBlockImpl extends GroovyPsiElementImpl implements GrCode @Nullable public PsiElement getLBrace() { - return findChildByType(GroovyTokenTypes.mLCURLY); + return findPsiChildByType(GroovyTokenTypes.mLCURLY); } @Nullable public PsiElement getRBrace() { - return findChildByType(GroovyTokenTypes.mRCURLY); + return findPsiChildByType(GroovyTokenTypes.mRCURLY); } public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java index 130647ec42a7..e6d1488e6c06 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java @@ -19,6 +19,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks; import com.intellij.lang.ASTNode; import com.intellij.psi.*; import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; @@ -54,8 +55,8 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock private volatile GrParameter mySyntheticItParameter; private GrVariable myOwner; - public GrClosableBlockImpl(@NotNull ASTNode node) { - super(node); + public GrClosableBlockImpl(@NotNull IElementType type, CharSequence buffer) { + super(type, buffer); } public void accept(GroovyElementVisitor visitor) { @@ -132,7 +133,7 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock @Override @Nullable public PsiElement getArrow() { - return findChildByType(GroovyTokenTypes.mCLOSABLE_BLOCK_OP); + return findPsiChildByType(GroovyTokenTypes.mCLOSABLE_BLOCK_OP); } public GrParameterListImpl getParameterList() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrOpenBlockImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrOpenBlockImpl.java index 9a8b933089b0..1e6a7e8157b7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrOpenBlockImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrOpenBlockImpl.java @@ -16,18 +16,17 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks; -import com.intellij.lang.ASTNode; +import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; /** * @author ilyas */ public class GrOpenBlockImpl extends GrBlockImpl implements GrOpenBlock { - - public GrOpenBlockImpl(@NotNull ASTNode node) { - super(node); + public GrOpenBlockImpl(@NotNull IElementType type, CharSequence buffer) { + super(type, buffer); } public void accept(GroovyElementVisitor visitor) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyPatterns.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyPatterns.java index b797248684c0..e5d13e935443 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyPatterns.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/patterns/GroovyPatterns.java @@ -19,6 +19,7 @@ import com.intellij.patterns.*; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; @@ -27,11 +28,16 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl; + +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_LITERAL; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mSTRING_LITERAL; public class GroovyPatterns extends PsiJavaPatterns { @@ -56,6 +62,23 @@ public class GroovyPatterns extends PsiJavaPatterns { }); } + public static GroovyElementPattern.Capture stringLiteral() { + return new GroovyElementPattern.Capture(new InitialPatternCondition(GrLiteralImpl.class) { + public boolean accepts(@Nullable final Object o, final ProcessingContext context) { + if (!(o instanceof GrLiteralImpl)) return false; + PsiElement child = ((GrLiteralImpl)o).getFirstChild(); + if (child == null) return false; + + IElementType elementType = child.getNode().getElementType(); + return elementType == mGSTRING_LITERAL || elementType == mSTRING_LITERAL; + } + }); + } + + public static GroovyElementPattern.Capture namedArgumentStringLiteral() { + return stringLiteral().withParent(psiElement(GrNamedArgument.class)); + } + public static GroovyMethodCallPattern methodCall(final ElementPattern names, final String className) { return new GroovyMethodCallPattern().with(new PatternCondition("methodCall") { public boolean accepts(@NotNull GrCallExpression callExpression, ProcessingContext context) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index 14caa5c9b638..ae581d9070f4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -520,8 +520,8 @@ public class ResolveUtil { return resolveResult != null && isInUseScope(resolveResult.getCurrentFileResolveContext()); } - public static boolean isInUseScope(PsiElement context) { - if (context instanceof GrMethodCall) { + public static boolean isInUseScope(@Nullable PsiElement context) { + if (context instanceof GrMethodCall && context.isValid()) { final GrExpression expression = ((GrMethodCall)context).getInvokedExpression(); if (expression instanceof GrReferenceExpression) { final PsiElement resolved = ((GrReferenceExpression)expression).resolve(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties index 5272d82ebb20..5e3e6a7a15af 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties @@ -150,6 +150,7 @@ expression.contains.errors=Expression contains errors field.0.is.already.defined=Field {0} is already defined access.to.created.field.0.will.be.overriden.by.method.1=Access to field {0} will be overriden by {1} final.field.cant.be.initialized.in.cur.method=Final field cannot be initialized in current method -Field.cannot.be.final.because.replaced.variable.has.lhs.usages=Field cannot be final because replaced variable is assigned new values several times +Field.cannot.be.final.because.replaced.variable.has.lhs.usages=Selected variable is used for write field.cannot.be.initialized.in.field.declaration=Field cannot be initialized in declaration field.cannot.be.initialized.in.constructor(s)=Field cannot be initialized in constructor(s) +selected.variable.is.used.for.write=Selected variable is used for write diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceContext.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceContext.java index d6937db28b17..184289237cb9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceContext.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceContext.java @@ -15,6 +15,9 @@ package org.jetbrains.plugins.groovy.refactoring.introduce; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; /** @@ -23,15 +26,24 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres public class GrIntroduceContext { public final Project project; public final Editor editor; - public final GrExpression expression; + @Nullable public final GrExpression expression; public final PsiElement[] occurrences; public final PsiElement scope; + @Nullable public final GrVariable var; + @NotNull public final PsiElement place; - public GrIntroduceContext(Project project, Editor editor, GrExpression expression, PsiElement[] occurrences, PsiElement scope) { + public GrIntroduceContext(Project project, + Editor editor, + GrExpression expression, + PsiElement[] occurrences, + PsiElement scope, + @Nullable GrVariable var) { this.project = project; this.editor = editor; this.expression = expression; this.occurrences = occurrences; this.scope = scope; + this.var = var; + this.place = expression == null ? var : expression; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java index db95a9fc2bfb..02005c549138 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java @@ -24,10 +24,13 @@ import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.wm.WindowManager; import com.intellij.psi.*; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.IntroduceTargetChooser; @@ -35,19 +38,23 @@ import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.util.Function; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrForStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrIfStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrWhileStatement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrStringInjection; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; import org.jetbrains.plugins.groovy.refactoring.NameValidator; +import org.jetbrains.plugins.groovy.refactoring.introduce.field.GrIntroduceFieldHandler; import java.util.ArrayList; import java.util.List; @@ -61,36 +68,21 @@ public abstract class GrIntroduceHandlerBase getDialog(GrIntroduceContext context); - public abstract void runRefactoring(GrIntroduceContext context, Settings settings); + @Nullable + public abstract GrVariable runRefactoring(GrIntroduceContext context, Settings settings); public static List collectExpressions(final PsiFile file, final Editor editor, final int offset) { - Document document = editor.getDocument(); - CharSequence text = document.getCharsSequence(); - int correctedOffset = offset; - int textLength = document.getTextLength(); - if (offset >= textLength) { - correctedOffset = textLength - 1; - } - else if (!Character.isJavaIdentifierPart(text.charAt(offset))) { - correctedOffset--; - } - if (correctedOffset < 0) { - correctedOffset = offset; - } - else if (!Character.isJavaIdentifierPart(text.charAt(correctedOffset))) { - if (text.charAt(correctedOffset) == ';') {//initially caret on the end of line - correctedOffset--; - } - if (text.charAt(correctedOffset) != ')') { - correctedOffset = offset; - } - } + int correctedOffset = correctOffset(editor, offset); final PsiElement elementAtCaret = file.findElementAt(correctedOffset); final List expressions = new ArrayList(); @@ -113,6 +105,40 @@ public abstract class GrIntroduceHandlerBase= textLength) { + correctedOffset = textLength - 1; + } + else if (!Character.isJavaIdentifierPart(text.charAt(offset))) { + correctedOffset--; + } + if (correctedOffset < 0) { + correctedOffset = offset; + } + else if (!Character.isJavaIdentifierPart(text.charAt(correctedOffset))) { + if (text.charAt(correctedOffset) == ';') {//initially caret on the end of line + correctedOffset--; + } + if (text.charAt(correctedOffset) != ')') { + correctedOffset = offset; + } + } + return correctedOffset; + } + + @Nullable + private static GrVariable findVariableAtCaret(final PsiFile file, final Editor editor, final int offset) { + final int correctOffset = correctOffset(editor, offset); + final PsiElement elementAtCaret = file.findElementAt(correctOffset); + final GrVariable variable = PsiTreeUtil.getParentOfType(elementAtCaret, GrVariable.class); + if (variable != null && variable.getNameIdentifierGroovy().getTextRange().contains(correctOffset)) return variable; + return null; + } + public void invoke(final @NotNull Project project, final Editor editor, final PsiFile file, final @Nullable DataContext dataContext) { final SelectionModel selectionModel = editor.getSelectionModel(); if (!selectionModel.hasSelection()) { @@ -120,7 +146,14 @@ public abstract class GrIntroduceHandlerBase expressions = collectExpressions(file, editor, offset); if (expressions.isEmpty()) { - selectionModel.selectLineAtCaret(); + final GrVariable variable = findVariableAtCaret(file, editor, offset); + if (variable == null || variable instanceof GrField || variable instanceof GrParameter) { + selectionModel.selectLineAtCaret(); + } + else { + final TextRange textRange = variable.getTextRange(); + selectionModel.setSelection(textRange.getStartOffset(), textRange.getEndOffset()); + } } else if (expressions.size() == 1) { final TextRange textRange = expressions.get(0).getTextRange(); @@ -151,11 +184,29 @@ public abstract class GrIntroduceHandlerBase list = new ArrayList(); + ReferencesSearch.search(variable, new LocalSearchScope(scope)).forEach(new Processor() { + @Override + public boolean process(PsiReference psiReference) { + final PsiElement element = psiReference.getElement(); + if (element != null) { + list.add(element); + } + return true; + } + }); + return new GrIntroduceContext(project, editor, variable.getInitializerGroovy(), list.toArray(new PsiElement[list.size()]), scope, + variable); + } } protected PsiElement[] findOccurences(GrExpression expression, PsiElement scope) { @@ -177,20 +228,34 @@ public abstract class GrIntroduceHandlerBase() { + public GrVariable compute() { + return runRefactoring(context, settings); } }); + + if (editor != null && created != null) { + PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); + editor.getCaretModel().moveToOffset(created.getNameIdentifierGroovy().getTextOffset()); + } } }, getRefactoringName(), null); @@ -203,10 +268,29 @@ public abstract class GrIntroduceHandlerBase isOKImpl(String varName, boolean replaceAllOccurrences) { - GrExpression firstOccurence; + PsiElement firstOccurence; if (replaceAllOccurrences) { - GroovyRefactoringUtil.sortOccurrences(myContext.occurrences); - firstOccurence = ((GrExpression)myContext.occurrences[0]); + if (myContext.occurrences.length > 0) { + GroovyRefactoringUtil.sortOccurrences(myContext.occurrences); + firstOccurence = myContext.occurrences[0]; + } + else { + firstOccurence = myContext.place; + } } else { firstOccurence = myContext.expression; } final MultiMap conflicts = new MultiMap(); assert varName != null; - validateOccurrencesDown(myContext.scope, conflicts, varName, firstOccurence.getTextRange().getStartOffset()); + + final int offset = firstOccurence.getTextRange().getStartOffset(); + validateOccurrencesDown(myContext.scope, conflicts, varName, offset); if (!(myContext.scope instanceof GroovyFileBase)) { - validateVariableOccurrencesUp(myContext.scope, conflicts, varName, firstOccurence.getTextRange().getStartOffset()); + validateVariableOccurrencesUp(myContext.scope, conflicts, varName, offset); } return conflicts; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantDialog.java index 90511719c3b2..649cfaf12adf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantDialog.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantDialog.java @@ -102,7 +102,7 @@ public class GrIntroduceConstantDialog extends DialogWrapper myTypeCombo.setEnabled(mySpecifyType.isSelected()); } }); - mySpecifyType.setSelected(context.expression.getType() != null); + mySpecifyType.setSelected(context.expression == null ? context.var.getDeclaredType() != null : context.expression.getType() != null); myTypeCombo.setEnabled(mySpecifyType.isSelected()); updateVisibilityPanel(); updateOkStatus(); @@ -121,7 +121,11 @@ public class GrIntroduceConstantDialog extends DialogWrapper initializeName(); initializeTargetClassEditor(); - if (myContext.occurrences.length < 2) { + if (myContext.var != null) { + myReplaceAllOccurences.setEnabled(false); + myReplaceAllOccurences.setSelected(true); + } + else if (myContext.occurrences.length < 2) { myReplaceAllOccurences.setVisible(false); } return myPanel; @@ -196,6 +200,9 @@ public class GrIntroduceConstantDialog extends DialogWrapper } }, KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.ALT_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW); + if (myContext.var != null) { + myNameComboBox.addItem(myContext.var.getName()); + } String[] possibleNames = GroovyNameSuggestionUtil.suggestVariableNames(myContext.expression, new GroovyVariableValidator(myContext), true); for (String possibleName : possibleNames) { myNameComboBox.addItem(possibleName); @@ -221,7 +228,13 @@ public class GrIntroduceConstantDialog extends DialogWrapper private void initializeTypeCombo() { - final PsiType expressionType = myContext.expression.getType(); + final PsiType expressionType; + if (myContext.expression != null) { + expressionType = myContext.expression.getType(); + } + else { + expressionType = myContext.var.getDeclaredType(); + } if (expressionType != null) { myTypes = GroovyRefactoringUtil.getCompatibleTypeNames(expressionType); for (String typeName : myTypes.keySet()) { @@ -358,7 +371,7 @@ public class GrIntroduceConstantDialog extends DialogWrapper if (myDefaultTargetClass == null || !"".equals(targetClassName) && !Comparing.strEqual(targetClassName, myDefaultTargetClass.getQualifiedName())) { - final Module module = ModuleUtil.findModuleForPsiElement(myContext.expression); + final Module module = ModuleUtil.findModuleForPsiElement(myContext.place); newClass = JavaPsiFacade.getInstance(myContext.project).findClass(targetClassName, module.getModuleScope()); if (newClass == null) { if (Messages.showOkCancelDialog(myContext.project, GroovyRefactoringBundle.message("class.does.not.exist.in.the.module"), @@ -366,12 +379,12 @@ public class GrIntroduceConstantDialog extends DialogWrapper return; } myTargetClass = - getTargetClass(targetClassName, myContext.expression.getContainingFile().getContainingDirectory(), myContext.project, module); + getTargetClass(targetClassName, myContext.place.getContainingFile().getContainingDirectory(), myContext.project, module); if (myTargetClass == null) return; } else { myTargetClass = - getTargetClass(targetClassName, myContext.expression.getContainingFile().getContainingDirectory(), myContext.project, module); + getTargetClass(targetClassName, myContext.place.getContainingFile().getContainingDirectory(), myContext.project, module); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantHandler.java index b307e4a21383..3e59ee304806 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantHandler.java @@ -25,6 +25,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -58,8 +59,9 @@ public class GrIntroduceConstantHandler extends GrIntroduceHandlerBase getDialog(GrIntroduceContext context) { return new GrIntroduceFieldDialog(context); } @Override - public void runRefactoring(GrIntroduceContext context, GrIntroduceFieldSettings settings) { + public GrField runRefactoring(GrIntroduceContext context, GrIntroduceFieldSettings settings) { final PsiClass targetClass = (PsiClass)context.scope; - if (targetClass == null) return; + if (targetClass == null) return null; final GrVariableDeclaration declaration = createField(context, settings); @@ -126,6 +141,7 @@ public class GrIntroduceFieldHandler extends GrIntroduceHandlerBase elements = ContainerUtil.findAll(context.occurrences, new Condition() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/variable/GroovyIntroduceVariableBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/variable/GroovyIntroduceVariableBase.java index 9072b19755b4..36fcef9941fc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/variable/GroovyIntroduceVariableBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/variable/GroovyIntroduceVariableBase.java @@ -56,7 +56,7 @@ public abstract class GroovyIntroduceVariableBase extends GrIntroduceHandlerBase @NotNull @Override - protected PsiElement findScope(GrExpression selectedExpr) { + protected PsiElement findScope(GrExpression selectedExpr, GrVariable variable) { // Get container element final PsiElement scope = GroovyRefactoringUtil.getEnclosingContainer(selectedExpr); @@ -88,6 +88,16 @@ public abstract class GroovyIntroduceVariableBase extends GrIntroduceHandlerBase } } + @Override + protected void checkVariable(GrVariable variable) throws GrIntroduceRefactoringError { + throw new GrIntroduceRefactoringError(null); + } + + @Override + protected void checkOccurrences(PsiElement[] occurrences) { + //nothing to do + } + private static boolean checkInFieldInitializer(GrExpression expr) { PsiElement parent = expr.getParent(); if (parent instanceof GrClosableBlock) { @@ -105,7 +115,7 @@ public abstract class GroovyIntroduceVariableBase extends GrIntroduceHandlerBase /** * Inserts new variable declaratrions and replaces occurrences */ - public void runRefactoring(final GrIntroduceContext context, final GroovyIntroduceVariableSettings settings) { + public GrVariable runRefactoring(final GrIntroduceContext context, final GroovyIntroduceVariableSettings settings) { // Generating varibable declaration final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(context.project); @@ -190,10 +200,12 @@ public abstract class GroovyIntroduceVariableBase extends GrIntroduceHandlerBase context.editor.getCaretModel().moveToOffset(getPositionMarker().getTextRange().getEndOffset()); context.editor.getSelectionModel().removeSelection(); } + return insertedVar; } catch (IncorrectOperationException e) { LOG.error(e); } + return null; } private static void resolveLocalConflicts(PsiElement tempContainer, String varName) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/ui/GrTypeComboBox.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/ui/GrTypeComboBox.java index 1c069d9ebc83..80c3c2eb6276 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/ui/GrTypeComboBox.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/ui/GrTypeComboBox.java @@ -17,7 +17,6 @@ package org.jetbrains.plugins.groovy.refactoring.ui; import com.intellij.psi.PsiType; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; import javax.swing.*; @@ -27,19 +26,18 @@ import java.util.Map; * @author Maxim.Medvedev */ public class GrTypeComboBox extends JComboBox { - private final GrExpression myExpr; + private final PsiType myType; - public GrTypeComboBox(GrExpression expr) { + public GrTypeComboBox(PsiType type) { super(); - myExpr = expr; + myType = type; initialize(); } private void initialize() { - final PsiType expressionType = myExpr.getType(); addItem(new PsiTypeItem(null)); - if (expressionType != null) { - final Map myTypes = GroovyRefactoringUtil.getCompatibleTypeNames(expressionType); + if (myType != null) { + final Map myTypes = GroovyRefactoringUtil.getCompatibleTypeNames(myType); for (String typeName : myTypes.keySet()) { addItem(new PsiTypeItem(myTypes.get(typeName))); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java index f61eb23d3341..f7ab6d15a5cc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java @@ -154,7 +154,7 @@ public class GroovyScriptRunConfigurationProducer extends RuntimeConfigurationPr final String path = existing.getScriptPath(); if (path != null) { final PsiFile file = location.getPsiElement().getContainingFile(); - if (file instanceof GroovyFile) { + if (file instanceof GroovyFile && ((GroovyFile)file).isScript()) { final VirtualFile vfile = file.getVirtualFile(); if (vfile != null && FileUtil.toSystemIndependentName(path).equals(vfile.getPath())) { if (GroovyScriptTypeDetector.getScriptType((GroovyFile)file).isConfigurationByLocation(existing, location)) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java index ccf5d4ac2afa..23c522cd1a35 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java @@ -12,6 +12,7 @@ import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.impl.DebugUtil; import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor; @@ -352,4 +353,20 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { public void testResultOfAssignmentUsed() { doTest(new GroovyResultOfAssignmentUsedInspection()); } + + public void testCodeBlockReparse() throws IOException { + myFixture.configureByText("a.groovy", "foo 'a', {}"); + myFixture.checkHighlighting(true, false, false); + final String psiBefore = DebugUtil.psiToString(myFixture.getFile(), false); + + myFixture.type('\n'); + myFixture.checkHighlighting(true, false, false); + final String psiAfter = DebugUtil.psiToString(myFixture.getFile(), false); + + myFixture.configureByText("a.txt", psiBefore); + myFixture.checkResultByFile(getTestName(false) + "1.txt"); + + myFixture.configureByText("a.txt", psiAfter); + myFixture.checkResultByFile(getTestName(false) + "2.txt"); + } } \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy index b2bf5c57a515..82688c38d129 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy @@ -6,6 +6,8 @@ import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod import org.jetbrains.annotations.NotNull +import com.intellij.psi.PsiDocumentManager +import com.intellij.testFramework.IdeaTestUtil /** * @author peter @@ -35,4 +37,30 @@ class GroovyStressTest extends LightCodeInsightFixtureTestCase { } + public void testQuickIncrementalReparse() { + def story = '''scenario { + given "some precondition", { + // do something + } + when "I do some stuff", { + // foo bar code + } + then "something I expect happens", { + // some verification + } +} +''' + myFixture.configureByText 'a.groovy', story * 200 + "" + PsiDocumentManager.getInstance(project).commitAllDocuments() + + def start = System.currentTimeMillis() + + story.toCharArray().each { + myFixture.type it + PsiDocumentManager.getInstance(project).commitAllDocuments() + } + + IdeaTestUtil.assertTiming "slow", 7000, (System.currentTimeMillis() - start) + } + } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/IntroduceConstantTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/IntroduceConstantTest.java index bfbf3eb07a8d..d0befb488aa4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/IntroduceConstantTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/IntroduceConstantTest.java @@ -76,7 +76,7 @@ public class IntroduceConstantTest extends LightCodeInsightFixtureTestCase { final GrExpression expression = findExpression(editor); - final GrIntroduceContext context = handler.getContext(getProject(), editor, expression); + final GrIntroduceContext context = handler.getContext(getProject(), editor, expression, null); PsiClass targetClass; if (targetClassName == null) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduce/field/GrIntroduceFieldTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduce/field/GrIntroduceFieldTest.java index 16738ad4cc16..3fb1d816b8e4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduce/field/GrIntroduceFieldTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduce/field/GrIntroduceFieldTest.java @@ -61,6 +61,10 @@ public class GrIntroduceFieldTest extends LightCodeInsightFixtureTestCase { doTest(false, true, false, CUR_METHOD, true, null); } + public void testIntroduceLocalVarByDeclaration() { + doTest(false, true, false, FIELD_DECLARATION, true, null); + } + private void doTest(final boolean isStatic, final boolean removeLocal, final boolean declareFinal, diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableTest.java index 3a365236df9a..2d0f7b0d0821 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableTest.java @@ -119,7 +119,7 @@ public class IntroduceVariableTest extends LightCodeInsightFixtureTestCase { varType = null; } - final GrIntroduceContext context = new GrIntroduceContext(getProject(), myEditor, selectedExpr, occurences, tempContainer); + final GrIntroduceContext context = new GrIntroduceContext(getProject(), myEditor, selectedExpr, occurences, tempContainer, null); ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableValidatorTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableValidatorTest.java index f44fc3636c51..2306f8f6008c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableValidatorTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableValidatorTest.java @@ -88,7 +88,7 @@ public class IntroduceVariableValidatorTest extends LightCodeInsightFixtureTestC PsiElement[] occurences = GroovyRefactoringUtil.getExpressionOccurrences(PsiUtil.skipParentheses(selectedExpr, false), tempContainer); String varName = "preved"; GroovyVariableValidator validator = - new GroovyVariableValidator(new GrIntroduceContext(getProject(), myEditor, selectedExpr, occurences, tempContainer)); + new GroovyVariableValidator(new GrIntroduceContext(getProject(), myEditor, selectedExpr, occurences, tempContainer, null)); result = validator.isOKTest(varName, replaceAllOccurences); return result; } diff --git a/plugins/groovy/testdata/highlighting/CodeBlockReparse1.txt b/plugins/groovy/testdata/highlighting/CodeBlockReparse1.txt new file mode 100644 index 000000000000..d0b83681a66f --- /dev/null +++ b/plugins/groovy/testdata/highlighting/CodeBlockReparse1.txt @@ -0,0 +1,15 @@ +Groovy script + Call expression + Reference expression + PsiElement(identifier)('foo') + PsiWhiteSpace(' ') + Command arguments + Literal + PsiElement(string)(''a'') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Closable block + PsiElement({)('{') + Parameter list + + PsiElement(})('}') diff --git a/plugins/groovy/testdata/highlighting/CodeBlockReparse2.txt b/plugins/groovy/testdata/highlighting/CodeBlockReparse2.txt new file mode 100644 index 000000000000..fef1ed4bae98 --- /dev/null +++ b/plugins/groovy/testdata/highlighting/CodeBlockReparse2.txt @@ -0,0 +1,16 @@ +Groovy script + Call expression + Reference expression + PsiElement(identifier)('foo') + PsiWhiteSpace(' ') + Command arguments + Literal + PsiElement(string)(''a'') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Closable block + PsiElement({)('{') + PsiWhiteSpace('\n \n') + Parameter list + + PsiElement(})('}') diff --git a/plugins/groovy/testdata/parsing/groovy/statements/try_catch/try2.test b/plugins/groovy/testdata/parsing/groovy/statements/try_catch/try2.test index bda086c5d135..dc8152f79d14 100644 --- a/plugins/groovy/testdata/parsing/groovy/statements/try_catch/try2.test +++ b/plugins/groovy/testdata/parsing/groovy/statements/try_catch/try2.test @@ -70,4 +70,6 @@ Groovy script PsiWhiteSpace(' ') PsiElement(})('}') PsiErrorElement:'}' expected - \ No newline at end of file + + PsiErrorElement:'catch' or 'finally' expected + \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/introduceField/IntroduceLocalVarByDeclaration.groovy b/plugins/groovy/testdata/refactoring/introduceField/IntroduceLocalVarByDeclaration.groovy new file mode 100644 index 000000000000..ecb4e7fa0218 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/introduceField/IntroduceLocalVarByDeclaration.groovy @@ -0,0 +1,12 @@ +class Foo { + def bar = 3 + def foo() { + print "a" + + def a = 4 - bar + print a + a++ + a-=4 + print a + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/introduceField/IntroduceLocalVarByDeclaration_after.groovy b/plugins/groovy/testdata/refactoring/introduceField/IntroduceLocalVarByDeclaration_after.groovy new file mode 100644 index 000000000000..ca6ba2a27983 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/introduceField/IntroduceLocalVarByDeclaration_after.groovy @@ -0,0 +1,13 @@ +class Foo { + def bar = 3 + def f = 4 - bar + + def foo() { + print "a" + + print f + f++ + f -=4 + print f + } +} \ No newline at end of file diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java index 5ad9dbf38108..63a2ec4e13ac 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java @@ -26,6 +26,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiPackage; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.refactoring.listeners.RefactoringElementAdapter; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.rt.execution.junit.JUnitStarter; import org.jetbrains.annotations.NotNull; @@ -78,18 +79,10 @@ class TestMethod extends TestObject { final PsiMethod method = (PsiMethod)element; if (!method.getName().equals(configuration.getPersistentData().getMethodName())) return null; if (!method.getContainingClass().equals(configuration.myClass.getPsiElement())) return null; - return new RefactoringElementListener() { - public void elementMoved(@NotNull final PsiElement newElement) { - setMethod(configuration, (PsiMethod)newElement); - } - - public void elementRenamed(@NotNull final PsiElement newElement) { - setMethod(configuration, (PsiMethod)newElement); - } - - private void setMethod(final JUnitConfiguration configuration, final PsiMethod psiMethod) { + return new RefactoringElementAdapter() { + public void elementRenamedOrMoved(@NotNull final PsiElement newElement) { final boolean generatedName = configuration.isGeneratedName(); - configuration.getPersistentData().setTestMethod(PsiLocation.fromPsiElement(psiMethod)); + configuration.getPersistentData().setTestMethod(PsiLocation.fromPsiElement((PsiMethod)newElement)); if (generatedName) configuration.setGeneratedName(); } }; diff --git a/plugins/junit/src/com/intellij/execution/junit2/states/ComparisonFailureState.java b/plugins/junit/src/com/intellij/execution/junit2/states/ComparisonFailureState.java index e41bbcabb9cb..d4ef1319d866 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/states/ComparisonFailureState.java +++ b/plugins/junit/src/com/intellij/execution/junit2/states/ComparisonFailureState.java @@ -48,7 +48,7 @@ public class ComparisonFailureState extends FaultyState implements AbstractTestP myHyperlink.printOn(printer); } - public String getExpecteed() { + public String getExpected() { return myHyperlink.getLeft(); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenExternalExecutor.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenExternalExecutor.java index 34001b661226..9e900f85fc4b 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenExternalExecutor.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenExternalExecutor.java @@ -23,6 +23,7 @@ import com.intellij.execution.process.DefaultJavaProcessHandler; import com.intellij.execution.process.OSProcessHandler; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import org.jetbrains.annotations.NonNls; import org.jetbrains.idea.maven.facade.MavenFacadeConsole; @@ -35,12 +36,15 @@ public class MavenExternalExecutor extends MavenExecutor { @NonNls private static final String PHASE_INFO_REGEXP = "\\[INFO\\] \\[.*:.*\\]"; @NonNls private static final int INFO_PREFIX_SIZE = "[INFO] ".length(); + private final Project myProject; - public MavenExternalExecutor(MavenRunnerParameters parameters, + public MavenExternalExecutor(Project project, + MavenRunnerParameters parameters, MavenGeneralSettings coreSettings, MavenRunnerSettings runnerSettings, MavenConsole console) { super(parameters, coreSettings, runnerSettings, RunnerBundle.message("external.executor.caption"), console); + myProject = project; } public boolean execute(final ProgressIndicator indicator) { @@ -48,7 +52,7 @@ public class MavenExternalExecutor extends MavenExecutor { try { myProcessHandler = - new DefaultJavaProcessHandler(MavenExternalParameters.createJavaParameters(myParameters, myCoreSettings, myRunnerSettings)) { + new DefaultJavaProcessHandler(MavenExternalParameters.createJavaParameters(myProject, myParameters, myCoreSettings, myRunnerSettings)) { public void notifyTextAvailable(String text, Key outputType) { // todo move this logic to ConsoleAdapter class if (!myConsole.isSuppressed(text)) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenExternalParameters.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenExternalParameters.java index d42f7d0eeabc..440d2485ef72 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenExternalParameters.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenExternalParameters.java @@ -20,14 +20,17 @@ package org.jetbrains.idea.maven.execution; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.JavaParameters; -import com.intellij.execution.configurations.SimpleJavaParameters; +import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdk; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.encoding.EncodingManager; +import com.intellij.openapi.vfs.encoding.EncodingProjectManager; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.project.MavenGeneralSettings; import org.jetbrains.idea.maven.utils.MavenUtil; @@ -44,25 +47,10 @@ public class MavenExternalParameters { @NonNls private static final String JAVA_HOME = "JAVA_HOME"; @NonNls private static final String MAVEN_OPTS = "MAVEN_OPTS"; - public static void configureSimpleJavaParameters(final SimpleJavaParameters params, + public static JavaParameters createJavaParameters(@Nullable final Project project, final MavenRunnerParameters parameters, final MavenGeneralSettings coreSettings, final MavenRunnerSettings runnerSettings) throws ExecutionException { - params.setJdk(getJdk(runnerSettings.getJreName())); - for (String parameter : createVMParameters(new ArrayList(), "", runnerSettings)) { - params.getVMParametersList().add(parameter); - } - - for (String parameter : createMavenParameters(new ArrayList(), coreSettings, runnerSettings, parameters)) { - if (!StringUtil.isEmpty(parameter)) { - params.getProgramParametersList().add(parameter); - } - } - } - - public static JavaParameters createJavaParameters(final MavenRunnerParameters parameters, - final MavenGeneralSettings coreSettings, - final MavenRunnerSettings runnerSettings) throws ExecutionException { final JavaParameters params = new JavaParameters(); params.setWorkingDirectory(parameters.getWorkingDirFile()); @@ -80,6 +68,10 @@ public class MavenExternalParameters { } params.setMainClass(MAVEN_LAUNCHER_CLASS); + EncodingManager encodingManager = project == null + ? EncodingProjectManager.getInstance() + : EncodingProjectManager.getInstance(project); + params.setCharset(encodingManager.getDefaultCharset()); for (String parameter : createMavenParameters(new ArrayList(), coreSettings, runnerSettings, parameters)) { if (!StringUtil.isEmpty(parameter)) { @@ -251,7 +243,7 @@ public class MavenExternalParameters { private static String encodeProfiles(final Collection profiles) { final StringBuilder stringBuilder = new StringBuilder(); for (String profile : profiles) { - if(stringBuilder.length()!=0){ + if (stringBuilder.length() != 0) { stringBuilder.append(","); } stringBuilder.append(profile); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunConfiguration.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunConfiguration.java index 6b66d051ddca..4e67df1942cb 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunConfiguration.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunConfiguration.java @@ -70,7 +70,7 @@ public class MavenRunConfiguration extends RunConfigurationBase implements Locat JavaCommandLineState state = new JavaCommandLineState(env) { protected JavaParameters createJavaParameters() throws ExecutionException { return MavenExternalParameters - .createJavaParameters(mySettings.myRunnerParameters, mySettings.myGeneralSettings, mySettings.myRunnerSettings); + .createJavaParameters(env.getProject(), mySettings.myRunnerParameters, mySettings.myGeneralSettings, mySettings.myRunnerSettings); } @Override diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunner.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunner.java index 9efcdd118daa..aaaaa9931218 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunner.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunner.java @@ -169,6 +169,6 @@ public class MavenRunner extends SimpleProjectComponent implements PersistentSta MavenGeneralSettings coreSettings, MavenRunnerSettings runnerSettings, MavenConsole console) { - return new MavenExternalExecutor(taskParameters, coreSettings, runnerSettings, console); + return new MavenExternalExecutor(myProject, taskParameters, coreSettings, runnerSettings, console); } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form index e0e318517c93..34941f41efb3 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form @@ -3,7 +3,7 @@ - + @@ -104,12 +104,13 @@ - + +