diff --git a/RegExpSupport/gen/org/intellij/lang/regexp/_RegExLexer.java b/RegExpSupport/gen/org/intellij/lang/regexp/_RegExLexer.java index 24fa1e4c2829..9040c9d8e677 100644 --- a/RegExpSupport/gen/org/intellij/lang/regexp/_RegExLexer.java +++ b/RegExpSupport/gen/org/intellij/lang/regexp/_RegExLexer.java @@ -191,19 +191,19 @@ class _RegExLexer implements FlexLexer { "\1\17\1\20\1\21\1\22\1\2\1\23\1\24\1\25"+ "\1\26\1\27\1\30\1\31\1\30\1\32\1\33\1\34"+ "\1\10\1\35\1\2\1\36\1\37\1\23\1\40\1\41"+ - "\1\42\1\43\1\44\1\45\1\1\1\46\1\47\2\50"+ - "\1\51\1\52\1\0\1\53\1\54\1\55\1\56\1\57"+ - "\1\60\1\10\1\61\1\62\1\63\1\64\1\10\1\64"+ - "\1\65\2\66\1\67\1\70\1\71\1\72\1\73\1\74"+ - "\1\75\1\10\1\76\1\77\1\100\1\0\1\101\1\102"+ - "\1\103\1\104\1\0\1\105\1\106\1\107\1\110\1\111"+ - "\1\0\1\112\1\0\1\113\1\0\1\114\1\115\1\116"+ - "\2\72\1\117\1\120\1\121\1\122\1\123\1\124\1\125"+ - "\1\126\1\0\1\113\1\0\1\127\2\72\1\117\1\130"+ - "\1\113\1\72\1\117\1\72\1\131\4\72"; + "\1\42\1\43\1\44\1\45\1\1\1\26\1\46\1\47"+ + "\2\50\1\51\1\52\1\0\1\53\1\54\1\55\1\56"+ + "\1\57\1\60\1\10\1\61\1\62\1\63\1\64\1\10"+ + "\1\64\1\65\2\66\1\67\1\70\1\71\1\72\1\73"+ + "\1\74\1\75\1\10\1\76\1\77\1\100\1\0\1\101"+ + "\1\102\1\103\1\104\1\0\1\105\1\106\1\107\1\110"+ + "\1\111\1\0\1\112\1\0\1\113\1\0\1\114\1\115"+ + "\1\116\2\72\1\117\1\120\1\121\1\122\1\123\1\124"+ + "\1\125\1\126\1\0\1\113\1\0\1\127\2\72\1\117"+ + "\1\130\1\113\1\72\1\117\1\72\1\131\4\72"; private static int [] zzUnpackAction() { - int [] result = new int[138]; + int [] result = new int[139]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -235,20 +235,20 @@ class _RegExLexer implements FlexLexer { "\0\u03e0\0\u04d8\0\u03e0\0\u0516\0\u03e0\0\u0554\0\u03e0\0\u03e0"+ "\0\u03e0\0\u0592\0\u03e0\0\u05d0\0\u03e0\0\u060e\0\u03e0\0\u064c"+ "\0\u03e0\0\u03e0\0\u045c\0\u03e0\0\u03e0\0\u03e0\0\u068a\0\u06c8"+ - "\0\u03e0\0\u03e0\0\u03e0\0\u03e0\0\u03e0\0\u0706\0\u0744\0\u03e0"+ - "\0\u0782\0\u07c0\0\u03e0\0\u07fe\0\u083c\0\u03e0\0\u03e0\0\u03e0"+ - "\0\u03e0\0\u03e0\0\u03e0\0\u087a\0\u08b8\0\u03e0\0\u03e0\0\u08f6"+ - "\0\u03e0\0\u03e0\0\u03e0\0\u03e0\0\u0934\0\u0972\0\u03e0\0\u03e0"+ - "\0\u09b0\0\u03e0\0\u03e0\0\u03e0\0\u09ee\0\u03e0\0\u03e0\0\u03e0"+ - "\0\u03e0\0\u0a2c\0\u0a6a\0\u03e0\0\u03e0\0\u03e0\0\u03e0\0\u0aa8"+ - "\0\u03e0\0\u0ae6\0\u0b24\0\u0b62\0\u03e0\0\u03e0\0\u03e0\0\u0ba0"+ - "\0\u0bde\0\u0c1c\0\u03e0\0\u03e0\0\u03e0\0\u03e0\0\u03e0\0\u03e0"+ - "\0\u03e0\0\u0c5a\0\u0c98\0\u0cd6\0\u03e0\0\u0d14\0\u03e0\0\u0d52"+ - "\0\u03e0\0\u03e0\0\u0d90\0\u0dce\0\u0e0c\0\u03e0\0\u0e4a\0\u0e88"+ - "\0\u0ec6\0\u0f04"; + "\0\u03e0\0\u03e0\0\u0706\0\u03e0\0\u03e0\0\u03e0\0\u0744\0\u0782"+ + "\0\u03e0\0\u07c0\0\u07fe\0\u03e0\0\u083c\0\u087a\0\u03e0\0\u03e0"+ + "\0\u03e0\0\u03e0\0\u03e0\0\u03e0\0\u08b8\0\u08f6\0\u03e0\0\u03e0"+ + "\0\u0934\0\u03e0\0\u03e0\0\u03e0\0\u03e0\0\u0972\0\u09b0\0\u03e0"+ + "\0\u03e0\0\u09ee\0\u03e0\0\u03e0\0\u03e0\0\u0a2c\0\u03e0\0\u03e0"+ + "\0\u03e0\0\u03e0\0\u0a6a\0\u0aa8\0\u03e0\0\u03e0\0\u03e0\0\u03e0"+ + "\0\u0ae6\0\u03e0\0\u0b24\0\u0b62\0\u0ba0\0\u03e0\0\u03e0\0\u03e0"+ + "\0\u0bde\0\u0c1c\0\u0c5a\0\u03e0\0\u03e0\0\u03e0\0\u03e0\0\u03e0"+ + "\0\u03e0\0\u03e0\0\u0c98\0\u0cd6\0\u0d14\0\u03e0\0\u0d52\0\u03e0"+ + "\0\u0d90\0\u03e0\0\u03e0\0\u0dce\0\u0e0c\0\u0e4a\0\u03e0\0\u0e88"+ + "\0\u0ec6\0\u0f04\0\u0f42"; private static int [] zzUnpackRowMap() { - int [] result = new int[138]; + int [] result = new int[139]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -287,66 +287,67 @@ class _RegExLexer implements FlexLexer { "\1\64\7\43\1\64\4\43\1\64\20\43\1\62\1\43"+ "\1\63\1\43\1\27\63\43\5\65\1\66\5\65\1\67"+ "\1\65\1\70\10\65\26\67\1\65\3\67\3\65\1\67"+ - "\4\65\1\71\5\65\65\13\1\72\10\13\13\65\1\46"+ - "\12\65\26\46\1\65\3\46\3\65\1\46\6\65\1\73"+ - "\16\65\1\46\12\65\26\46\1\65\3\46\1\65\1\74"+ - "\1\65\1\46\17\65\1\66\5\65\1\46\12\65\26\46"+ - "\1\65\3\46\3\65\1\46\13\65\2\44\2\65\1\66"+ - "\5\65\1\46\3\65\1\44\6\65\26\46\1\44\3\46"+ - "\3\65\1\46\12\65\13\75\1\46\4\75\1\32\5\75"+ - "\26\46\1\75\3\46\3\75\1\46\4\75\1\76\5\75"+ - "\120\0\1\77\64\0\1\100\1\101\5\0\1\102\55\0"+ - "\1\103\1\104\1\105\4\106\1\103\1\107\1\103\1\107"+ - "\1\110\1\103\1\111\1\112\1\103\1\107\5\106\2\113"+ - "\1\114\1\115\3\116\3\117\1\120\2\121\2\122\3\123"+ - "\1\110\1\124\1\125\1\126\1\104\1\127\1\130\1\131"+ - "\2\103\1\112\1\110\1\103\1\112\1\103\1\112\6\103"+ - "\47\0\1\132\27\0\2\44\14\0\1\44\34\0\1\44"+ + "\4\65\1\71\5\65\65\13\1\72\10\13\13\65\1\73"+ + "\12\65\26\73\1\65\3\73\3\65\1\73\6\65\1\74"+ + "\16\65\1\73\12\65\26\73\1\65\3\73\1\65\1\75"+ + "\1\65\1\73\17\65\1\66\5\65\1\73\12\65\26\73"+ + "\1\65\3\73\3\65\1\73\13\65\2\44\2\65\1\66"+ + "\5\65\1\73\3\65\1\44\6\65\26\73\1\44\3\73"+ + "\3\65\1\73\12\65\13\76\1\46\4\76\1\32\5\76"+ + "\26\46\1\76\3\46\3\76\1\46\4\76\1\77\5\76"+ + "\120\0\1\100\64\0\1\101\1\102\5\0\1\103\55\0"+ + "\1\104\1\105\1\106\4\107\1\104\1\110\1\104\1\110"+ + "\1\111\1\104\1\112\1\113\1\104\1\110\5\107\2\114"+ + "\1\115\1\116\3\117\3\120\1\121\2\122\2\123\3\124"+ + "\1\111\1\125\1\126\1\127\1\105\1\130\1\131\1\132"+ + "\2\104\1\113\1\111\1\104\1\113\1\104\1\113\6\104"+ + "\47\0\1\133\27\0\2\44\14\0\1\44\34\0\1\44"+ "\22\0\2\46\1\0\2\46\5\0\5\46\6\0\32\46"+ - "\3\0\1\46\23\0\1\133\75\0\1\134\1\135\5\0"+ - "\1\102\47\0\1\136\5\0\1\103\1\104\1\105\4\106"+ - "\1\103\3\107\1\110\1\103\1\111\1\112\1\103\1\107"+ - "\5\106\2\113\1\114\1\115\3\116\3\117\1\120\2\121"+ - "\2\122\3\123\1\110\1\124\1\125\1\126\1\104\1\127"+ - "\1\130\1\131\2\103\1\112\1\110\1\103\1\112\1\103"+ - "\1\112\6\103\71\0\1\137\17\0\1\67\12\0\26\67"+ + "\3\0\1\46\23\0\1\134\75\0\1\135\1\136\5\0"+ + "\1\103\47\0\1\137\5\0\1\104\1\105\1\106\4\107"+ + "\1\104\3\110\1\111\1\104\1\112\1\113\1\104\1\110"+ + "\5\107\2\114\1\115\1\116\3\117\3\120\1\121\2\122"+ + "\2\123\3\124\1\111\1\125\1\126\1\127\1\105\1\130"+ + "\1\131\1\132\2\104\1\113\1\111\1\104\1\113\1\104"+ + "\1\113\6\104\71\0\1\140\17\0\1\67\12\0\26\67"+ "\1\0\3\67\3\0\1\67\25\0\1\70\12\0\26\70"+ - "\1\0\3\70\3\0\1\70\23\0\1\140\70\0\1\141"+ - "\37\0\1\142\13\0\1\143\1\144\6\0\1\145\1\0"+ - "\1\145\1\146\1\147\1\150\11\0\1\100\75\0\1\151"+ - "\1\152\64\0\2\104\51\0\1\104\23\0\1\153\51\0"+ - "\1\153\27\0\1\154\147\0\1\155\1\156\14\0\76\157"+ - "\1\0\2\160\3\0\1\161\20\0\2\160\1\0\1\160"+ - "\4\0\3\160\5\0\2\160\3\0\1\160\22\0\2\162"+ - "\24\0\2\162\1\0\1\162\4\0\3\162\5\0\2\162"+ - "\3\0\1\162\101\0\1\163\1\164\25\0\1\165\144\0"+ - "\1\166\12\0\1\167\75\0\1\170\1\171\1\0\5\172"+ - "\1\0\70\172\11\0\1\151\66\0\1\173\51\0\1\173"+ - "\52\0\1\174\45\0\2\175\24\0\2\175\1\0\1\175"+ - "\4\0\3\175\5\0\2\175\3\0\1\175\22\0\2\176"+ - "\4\0\1\177\17\0\2\176\1\0\1\176\4\0\3\176"+ - "\5\0\2\176\3\0\1\176\22\0\2\200\24\0\2\200"+ - "\1\0\1\200\4\0\3\200\5\0\2\200\3\0\1\200"+ - "\21\0\5\172\1\201\70\172\2\0\1\202\51\0\1\202"+ - "\30\0\1\116\67\0\2\203\4\0\1\175\17\0\2\203"+ - "\1\0\1\203\4\0\3\203\5\0\2\203\3\0\1\203"+ - "\22\0\2\204\24\0\2\204\1\0\1\204\4\0\3\204"+ - "\5\0\2\204\3\0\1\204\22\0\2\205\4\0\1\175"+ - "\17\0\2\205\1\0\1\205\4\0\3\205\5\0\2\205"+ - "\3\0\1\205\22\0\2\206\24\0\2\206\1\0\1\206"+ - "\4\0\3\206\5\0\2\206\3\0\1\206\22\0\2\207"+ - "\4\0\1\175\17\0\2\207\1\0\1\207\4\0\3\207"+ - "\5\0\2\207\3\0\1\207\22\0\2\210\4\0\1\175"+ - "\17\0\2\210\1\0\1\210\4\0\3\210\5\0\2\210"+ - "\3\0\1\210\22\0\2\211\4\0\1\175\17\0\2\211"+ - "\1\0\1\211\4\0\3\211\5\0\2\211\3\0\1\211"+ - "\22\0\2\212\4\0\1\175\17\0\2\212\1\0\1\212"+ - "\4\0\3\212\5\0\2\212\3\0\1\212\22\0\2\212"+ - "\4\0\1\177\17\0\2\212\1\0\1\212\4\0\3\212"+ - "\5\0\2\212\3\0\1\212\21\0"; + "\1\0\3\70\3\0\1\70\13\0\2\73\10\0\5\73"+ + "\6\0\32\73\3\0\1\73\23\0\1\141\70\0\1\142"+ + "\37\0\1\143\13\0\1\144\1\145\6\0\1\146\1\0"+ + "\1\146\1\147\1\150\1\151\11\0\1\101\75\0\1\152"+ + "\1\153\64\0\2\105\51\0\1\105\23\0\1\154\51\0"+ + "\1\154\27\0\1\155\147\0\1\156\1\157\14\0\76\160"+ + "\1\0\2\161\3\0\1\162\20\0\2\161\1\0\1\161"+ + "\4\0\3\161\5\0\2\161\3\0\1\161\22\0\2\163"+ + "\24\0\2\163\1\0\1\163\4\0\3\163\5\0\2\163"+ + "\3\0\1\163\101\0\1\164\1\165\25\0\1\166\144\0"+ + "\1\167\12\0\1\170\75\0\1\171\1\172\1\0\5\173"+ + "\1\0\70\173\11\0\1\152\66\0\1\174\51\0\1\174"+ + "\52\0\1\175\45\0\2\176\24\0\2\176\1\0\1\176"+ + "\4\0\3\176\5\0\2\176\3\0\1\176\22\0\2\177"+ + "\4\0\1\200\17\0\2\177\1\0\1\177\4\0\3\177"+ + "\5\0\2\177\3\0\1\177\22\0\2\201\24\0\2\201"+ + "\1\0\1\201\4\0\3\201\5\0\2\201\3\0\1\201"+ + "\21\0\5\173\1\202\70\173\2\0\1\203\51\0\1\203"+ + "\30\0\1\117\67\0\2\204\4\0\1\176\17\0\2\204"+ + "\1\0\1\204\4\0\3\204\5\0\2\204\3\0\1\204"+ + "\22\0\2\205\24\0\2\205\1\0\1\205\4\0\3\205"+ + "\5\0\2\205\3\0\1\205\22\0\2\206\4\0\1\176"+ + "\17\0\2\206\1\0\1\206\4\0\3\206\5\0\2\206"+ + "\3\0\1\206\22\0\2\207\24\0\2\207\1\0\1\207"+ + "\4\0\3\207\5\0\2\207\3\0\1\207\22\0\2\210"+ + "\4\0\1\176\17\0\2\210\1\0\1\210\4\0\3\210"+ + "\5\0\2\210\3\0\1\210\22\0\2\211\4\0\1\176"+ + "\17\0\2\211\1\0\1\211\4\0\3\211\5\0\2\211"+ + "\3\0\1\211\22\0\2\212\4\0\1\176\17\0\2\212"+ + "\1\0\1\212\4\0\3\212\5\0\2\212\3\0\1\212"+ + "\22\0\2\213\4\0\1\176\17\0\2\213\1\0\1\213"+ + "\4\0\3\213\5\0\2\213\3\0\1\213\22\0\2\213"+ + "\4\0\1\200\17\0\2\213\1\0\1\213\4\0\3\213"+ + "\5\0\2\213\3\0\1\213\21\0"; private static int [] zzUnpackTrans() { - int [] result = new int[3906]; + int [] result = new int[3968]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -387,15 +388,15 @@ class _RegExLexer implements FlexLexer { "\12\0\1\1\5\0\2\11\1\1\2\11\2\1\12\11"+ "\1\1\1\11\1\1\1\11\1\1\3\11\1\1\1\11"+ "\1\1\1\11\1\1\1\11\1\1\2\11\1\1\3\11"+ - "\2\1\5\11\2\1\1\11\1\0\1\1\1\11\2\1"+ - "\6\11\2\1\2\11\1\1\4\11\2\1\2\11\1\1"+ - "\3\11\1\0\4\11\1\0\1\1\4\11\1\0\1\11"+ - "\1\0\1\1\1\0\3\11\3\1\7\11\1\0\1\1"+ - "\1\0\1\11\1\1\1\11\1\1\2\11\3\1\1\11"+ - "\4\1"; + "\2\1\2\11\1\1\3\11\2\1\1\11\1\0\1\1"+ + "\1\11\2\1\6\11\2\1\2\11\1\1\4\11\2\1"+ + "\2\11\1\1\3\11\1\0\4\11\1\0\1\1\4\11"+ + "\1\0\1\11\1\0\1\1\1\0\3\11\3\1\7\11"+ + "\1\0\1\1\1\0\1\11\1\1\1\11\1\1\2\11"+ + "\3\1\1\11\4\1"; private static int [] zzUnpackAttribute() { - int [] result = new int[138]; + int [] result = new int[139]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java index 06a6d3f3c77e..9c16d5334237 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java @@ -217,7 +217,8 @@ public class RegExpParser implements PsiParser { // DEFLIST if (parseClassIntersection(builder)) { - while (RegExpTT.CHARACTERS2.contains(builder.getTokenType()) || + while (RegExpTT.CHARACTERS.contains(builder.getTokenType()) || + builder.getTokenType() == RegExpTT.CHAR_CLASS || builder.getTokenType() == RegExpTT.CLASS_BEGIN || builder.getTokenType() == RegExpTT.PROPERTY || builder.getTokenType() == RegExpTT.BRACKET_EXPRESSION_BEGIN) { @@ -257,9 +258,14 @@ public class RegExpParser implements PsiParser { else if (token == RegExpTT.BRACKET_EXPRESSION_BEGIN) { parseBracketExpression(builder); } - else if (RegExpTT.CHARACTERS2.contains(token)) { + else if (RegExpTT.CHARACTERS.contains(token)) { parseSimpleClassdef(builder); } + else if (token == RegExpTT.CHAR_CLASS) { + final PsiBuilder.Marker m = builder.mark(); + builder.advanceLexer(); + m.done(RegExpElementTypes.SIMPLE_CLASS); + } else if (token == RegExpTT.PROPERTY) { parseProperty(builder); } @@ -291,7 +297,7 @@ public class RegExpParser implements PsiParser { } private void parseSimpleClassdef(PsiBuilder builder) { - assert RegExpTT.CHARACTERS2.contains(builder.getTokenType()); + assert RegExpTT.CHARACTERS.contains(builder.getTokenType()); final PsiBuilder.Marker marker = builder.mark(); makeChar(builder); @@ -301,7 +307,7 @@ public class RegExpParser implements PsiParser { builder.advanceLexer(); final IElementType t = builder.getTokenType(); - if (RegExpTT.CHARACTERS2.contains(t)) { + if (RegExpTT.CHARACTERS.contains(t) || t == RegExpTT.CHAR_CLASS) { m.drop(); makeChar(builder); marker.done(RegExpElementTypes.CHAR_RANGE); @@ -449,7 +455,7 @@ public class RegExpParser implements PsiParser { marker.drop(); parseNamedCharacter(builder); } - else if (RegExpTT.SIMPLE_CLASSES.contains(type)) { + else if (type == RegExpTT.DOT || type == RegExpTT.CHAR_CLASS) { builder.advanceLexer(); marker.done(RegExpElementTypes.SIMPLE_CLASS); } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpTT.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpTT.java index 6ad066f37b5d..2da30a8be0da 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpTT.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpTT.java @@ -135,22 +135,17 @@ public interface RegExpTT { IElementType RUBY_QUOTED_NAMED_GROUP_CALL = new RegExpElementType("RUBY_QUOTED_NAMED_GROUP_CALL"); TokenSet CHARACTERS = TokenSet.create(CHARACTER, - ESC_CTRL_CHARACTER, - ESC_CHARACTER, - CTRL_CHARACTER, - CTRL, - UNICODE_CHAR, - HEX_CHAR, BAD_HEX_VALUE, - OCT_CHAR, BAD_OCT_VALUE, - REDUNDANT_ESCAPE, - MINUS, - StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN, - StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN); - - TokenSet SIMPLE_CLASSES = TokenSet.create(DOT, CHAR_CLASS); - - // caret is just a character in classes after the first position: [a^] matches "a" or "^" - TokenSet CHARACTERS2 = TokenSet.orSet(CHARACTERS, SIMPLE_CLASSES); + ESC_CTRL_CHARACTER, + ESC_CHARACTER, + CTRL_CHARACTER, + CTRL, + UNICODE_CHAR, + HEX_CHAR, BAD_HEX_VALUE, + OCT_CHAR, BAD_OCT_VALUE, + REDUNDANT_ESCAPE, + MINUS, + StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN, + StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN); TokenSet QUANTIFIERS = TokenSet.create(QUEST, PLUS, STAR, LBRACE); diff --git a/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex b/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex index 16ff07395dab..d90f4964e2b2 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex +++ b/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex @@ -100,6 +100,7 @@ RBRACKET="]" ESCAPE="\\" NAME=[:letter:]([:letter:]|_|-|" "|"("|")"|[:digit:])* +GROUP_NAME=[:letter:]([:letter:]|_|-|" "|[:digit:])* ANY=[^] META1 = {ESCAPE} | {LBRACKET} | "^" @@ -340,25 +341,25 @@ HEX_CHAR=[0-9a-fA-F] } { - {NAME} { return RegExpTT.NAME; } + {GROUP_NAME} { return RegExpTT.NAME; } ">" { yybegin(YYINITIAL); return RegExpTT.GT; } {ANY} { yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER; } } { - {NAME} { return RegExpTT.NAME; } + {GROUP_NAME} { return RegExpTT.NAME; } "'" { yybegin(YYINITIAL); return RegExpTT.QUOTE; } {ANY} { yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER; } } { - {NAME} { return RegExpTT.NAME; } + {GROUP_NAME} { return RegExpTT.NAME; } ")" { yybegin(YYINITIAL); return RegExpTT.GROUP_END; } {ANY} { yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER; } } { - {NAME} { return RegExpTT.NAME; } + {GROUP_NAME} { return RegExpTT.NAME; } [:digit:]+ { return RegExpTT.NUMBER; } ")" { yybegin(YYINITIAL); return RegExpTT.GROUP_END; } {ANY} { yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER; } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java b/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java index 3618b81df854..ee1a4ad01fda 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java @@ -84,9 +84,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot public void visitRegExpCharRange(RegExpCharRange range) { final RegExpCharRange.Endpoint from = range.getFrom(); final RegExpCharRange.Endpoint to = range.getTo(); - final boolean a = from instanceof RegExpChar; - final boolean b = to instanceof RegExpChar; - if (a && b) { + if (from instanceof RegExpChar && to instanceof RegExpChar) { final Character t = ((RegExpChar)to).getValue(); final Character f = ((RegExpChar)from).getValue(); if (t != null && f != null) { @@ -99,8 +97,8 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot } } } - else if (a != b) { - myHolder.createErrorAnnotation(range, "Character class (e.g. '\\\\w') may not be used inside character range"); + else if (to instanceof RegExpSimpleClass) { + myHolder.createErrorAnnotation(to, "Character class not allowed inside character range"); } else if (from.getText().equals(to.getText())) { myHolder.createWarningAnnotation(range, "Redundant character range"); @@ -151,12 +149,20 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot } } - private void checkForDuplicates(RegExpClassElement element, Set seen) { + private void checkForDuplicates(RegExpClassElement element, Set seen) { if (element instanceof RegExpChar) { final RegExpChar regExpChar = (RegExpChar)element; final Character value = regExpChar.getValue(); if (value != null && !seen.add(value)) { - myHolder.createWarningAnnotation(regExpChar, "Duplicate character '" + regExpChar.getText() + "' in character class"); + myHolder.createWarningAnnotation(regExpChar, "Duplicate character '" + regExpChar.getText() + "' inside character class"); + } + } + else if (element instanceof RegExpSimpleClass) { + final RegExpSimpleClass regExpSimpleClass = (RegExpSimpleClass)element; + final RegExpSimpleClass.Kind kind = regExpSimpleClass.getKind(); + if (!seen.add(kind)) { + myHolder.createWarningAnnotation(regExpSimpleClass, "Duplicate predefined character class '" + regExpSimpleClass.getText() + + "' inside character class"); } } else if (element instanceof RegExpClass) { diff --git a/RegExpSupport/test/org/intellij/lang/regexp/RegExpParsingTest.java b/RegExpSupport/test/org/intellij/lang/regexp/RegExpParsingTest.java index f351c303a042..1d057c835fd0 100644 --- a/RegExpSupport/test/org/intellij/lang/regexp/RegExpParsingTest.java +++ b/RegExpSupport/test/org/intellij/lang/regexp/RegExpParsingTest.java @@ -184,6 +184,10 @@ public class RegExpParsingTest extends ParsingTestCase { public void testGroups33() throws IOException { doCodeTest("(?[a-c])\\1"); } public void testGroups34() throws IOException { doCodeTest("(?[a-c])\\k"); } public void testGroups35() throws IOException { doCodeTest("\\k"); } + public void testGroups36() throws IOException { doCodeTest("(?P{"); } + public void testGroups37() throws IOException { doCodeTest("(?P=name)"); } + public void testGroups38() throws IOException { doCodeTest("\\g'name'"); } + public void testGroups39() throws IOException { doCodeTest("(?(name)yes-pattern|no-pattern)"); } public void testEscapes1() throws IOException { doCodeTest("\\q"); } public void testEscapes2() throws IOException { doCodeTest("\\#"); } diff --git a/RegExpSupport/testData/RETest.xml b/RegExpSupport/testData/RETest.xml index 75ca74a4696f..8069ee6fd0f8 100644 --- a/RegExpSupport/testData/RETest.xml +++ b/RegExpSupport/testData/RETest.xml @@ -37,7 +37,11 @@ - \w-\w]]]> + \w]]]> + OK + + + [\w-a] OK @@ -106,7 +110,7 @@ OK - )]][]\E]]]> + )]][]\E]]]> OK @@ -133,7 +137,7 @@ OK - it:]+]]> + it:]+]]> OK diff --git a/RegExpSupport/testData/psi/Charclasses61.txt b/RegExpSupport/testData/psi/Charclasses61.txt index 01e2ae8f4b48..13bfb2cb45dc 100644 --- a/RegExpSupport/testData/psi/Charclasses61.txt +++ b/RegExpSupport/testData/psi/Charclasses61.txt @@ -3,10 +3,11 @@ REGEXP_FILE RegExpBranchImpl: <[\w-\w]> RegExpClassImpl: <[\w-\w]> PsiElement(CLASS_BEGIN)('[') - RegExpCharRangeImpl: <\w-\w> + RegExpUnionImpl: <\w-\w> RegExpSimpleClassImpl: <\w> PsiElement(CHAR_CLASS)('\w') - PsiElement(MINUS)('-') + RegExpCharImpl: <-> + PsiElement(MINUS)('-') RegExpSimpleClassImpl: <\w> PsiElement(CHAR_CLASS)('\w') PsiElement(CLASS_END)(']') \ No newline at end of file diff --git a/RegExpSupport/testData/psi/Groups36.txt b/RegExpSupport/testData/psi/Groups36.txt new file mode 100644 index 000000000000..bb6cfb567a65 --- /dev/null +++ b/RegExpSupport/testData/psi/Groups36.txt @@ -0,0 +1,14 @@ +REGEXP_FILE + RegExpPatternImpl: <(?P{> + RegExpBranchImpl: <(?P{> + RegExpClosureImpl: <(?P{> + RegExpGroupImpl: <(?P> + PsiElement(PYTHON_NAMED_GROUP)('(?P<') + PsiElement(NAME)('name') + PsiElement(GT)('>') + PsiErrorElement:Dangling metacharacter + + RegExpQuantifierImpl: <{> + PsiElement(LBRACE)('{') + PsiErrorElement:Number expected + \ No newline at end of file diff --git a/RegExpSupport/testData/psi/Groups37.txt b/RegExpSupport/testData/psi/Groups37.txt new file mode 100644 index 000000000000..7944e6527490 --- /dev/null +++ b/RegExpSupport/testData/psi/Groups37.txt @@ -0,0 +1,7 @@ +REGEXP_FILE + RegExpPatternImpl: <(?P=name)> + RegExpBranchImpl: <(?P=name)> + RegExpNamedGroupRefImpl: <(?P=name)> + PsiElement(PYTHON_NAMED_GROUP_REF)('(?P=') + PsiElement(NAME)('name') + PsiElement(GROUP_END)(')') \ No newline at end of file diff --git a/RegExpSupport/testData/psi/Groups38.txt b/RegExpSupport/testData/psi/Groups38.txt new file mode 100644 index 000000000000..5603f065cdd4 --- /dev/null +++ b/RegExpSupport/testData/psi/Groups38.txt @@ -0,0 +1,7 @@ +REGEXP_FILE + RegExpPatternImpl: <\g'name'> + RegExpBranchImpl: <\g'name'> + RegExpNamedGroupRefImpl: <\g'name'> + PsiElement(RUBY_QUOTED_NAMED_GROUP_CALL)('\g'') + PsiElement(NAME)('name') + PsiElement(QUOTE)(''') \ No newline at end of file diff --git a/RegExpSupport/testData/psi/Groups39.txt b/RegExpSupport/testData/psi/Groups39.txt new file mode 100644 index 000000000000..60bd9b26a375 --- /dev/null +++ b/RegExpSupport/testData/psi/Groups39.txt @@ -0,0 +1,53 @@ +REGEXP_FILE + RegExpPatternImpl: <(?(name)yes-pattern|no-pattern)> + RegExpBranchImpl: <(?(name)yes-pattern|no-pattern)> + RegExpPyCondRefImpl: <(?(name)yes-pattern|no-pattern)> + PsiElement(PYTHON_COND_REF)('(?(') + PsiElement(NAME)('name') + PsiElement(GROUP_END)(')') + RegExpBranchImpl: + RegExpCharImpl: + PsiElement(CHARACTER)('y') + RegExpCharImpl: + PsiElement(CHARACTER)('e') + RegExpCharImpl: + PsiElement(CHARACTER)('s') + RegExpCharImpl: <-> + PsiElement(MINUS)('-') + RegExpCharImpl:

+ PsiElement(CHARACTER)('p') + RegExpCharImpl: + PsiElement(CHARACTER)('a') + RegExpCharImpl: + PsiElement(CHARACTER)('t') + RegExpCharImpl: + PsiElement(CHARACTER)('t') + RegExpCharImpl: + PsiElement(CHARACTER)('e') + RegExpCharImpl: + PsiElement(CHARACTER)('r') + RegExpCharImpl: + PsiElement(CHARACTER)('n') + PsiElement(UNION)('|') + RegExpBranchImpl: + RegExpCharImpl: + PsiElement(CHARACTER)('n') + RegExpCharImpl: + PsiElement(CHARACTER)('o') + RegExpCharImpl: <-> + PsiElement(MINUS)('-') + RegExpCharImpl:

+ PsiElement(CHARACTER)('p') + RegExpCharImpl: + PsiElement(CHARACTER)('a') + RegExpCharImpl: + PsiElement(CHARACTER)('t') + RegExpCharImpl: + PsiElement(CHARACTER)('t') + RegExpCharImpl: + PsiElement(CHARACTER)('e') + RegExpCharImpl: + PsiElement(CHARACTER)('r') + RegExpCharImpl: + PsiElement(CHARACTER)('n') + PsiElement(GROUP_END)(')') \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java index 09314d8059ba..869eedc77d1c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexUtil.java @@ -26,7 +26,7 @@ import java.util.*; public class BackwardReferenceIndexUtil { static void registerFile(String filePath, - Set refs, + Collection refs, List defs, final BackwardReferenceIndexWriter writer) { final int fileId = writer.enumeratePath(filePath); diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java index 891572268ccd..b6fb8ee5177a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java @@ -19,16 +19,20 @@ import org.jetbrains.jps.javac.ast.api.JavacDef; import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar; import org.jetbrains.jps.javac.ast.api.JavacRef; +import java.util.Collection; import java.util.List; -import java.util.Set; public class BackwardReferenceRegistrar implements JavacFileReferencesRegistrar { - private BackwardReferenceIndexWriter myWriter; + private volatile BackwardReferenceIndexWriter myWriter; @Override - public boolean initialize() { + public void initialize() { myWriter = BackwardReferenceIndexWriter.getInstance(); - return myWriter != null; + } + + @Override + public boolean isEnabled() { + return BackwardReferenceIndexWriter.isEnabled(); } @Override @@ -37,7 +41,7 @@ public class BackwardReferenceRegistrar implements JavacFileReferencesRegistrar } @Override - public void registerFile(String filePath, Set refs, List defs) { + public void registerFile(String filePath, Collection refs, List defs) { BackwardReferenceIndexUtil.registerFile(filePath, refs, defs, myWriter); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 46dea9b6a6aa..400adc6de8f5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -1042,6 +1042,10 @@ public class JavaBuilder extends ModuleLevelBuilder { } } + for (JavaCompilerToolExtension extension : JavaCompilerToolExtension.getExtensions()) { + vmOptions.addAll(extension.getExternalBuildProcessOptions(compilingTool)); + } + compilingTool.processCompilerOptions(context, options); JAVAC_OPTIONS.set(context, options); diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavaCompilerToolExtension.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavaCompilerToolExtension.java index 92502508366a..650c67b0a87e 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavaCompilerToolExtension.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavaCompilerToolExtension.java @@ -22,6 +22,8 @@ import org.jetbrains.jps.service.JpsServiceManager; import javax.tools.*; import java.util.Collection; +import java.util.Collections; +import java.util.List; /** * @author Eugene Zhuravlev @@ -51,6 +53,10 @@ public abstract class JavaCompilerToolExtension { public void processData(String dataName, byte[] content) { } + public List getExternalBuildProcessOptions(@NotNull JavaCompilingTool compilingTool) { + return Collections.emptyList(); + } + public static Iterable getExtensions() { return JpsServiceManager.getInstance().getExtensions(JavaCompilerToolExtension.class); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java index 18e1d728961c..0231eb25ab84 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java @@ -15,6 +15,7 @@ */ package org.jetbrains.jps.javac.ast; +import com.intellij.util.Consumer; import com.intellij.util.ReflectionUtil; import com.sun.source.util.JavacTask; import com.sun.source.util.TaskEvent; @@ -27,7 +28,7 @@ import gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.jps.javac.ast.api.JavacDef; -import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar; +import org.jetbrains.jps.javac.ast.api.JavacFileData; import org.jetbrains.jps.javac.ast.api.JavacRef; import javax.lang.model.element.ElementKind; @@ -35,14 +36,11 @@ import javax.lang.model.element.TypeElement; import javax.tools.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; final class JavacReferenceCollectorListener implements TaskListener { - private final JavacFileReferencesRegistrar[] myFullASTListeners; - private final JavacFileReferencesRegistrar[] myOnlyImportsListeners; + private final boolean myDivideImportRefs; + private final Consumer myDataConsumer; private final JavacTreeRefScanner myAstScanner; private Name myAsterisk; @@ -50,11 +48,11 @@ final class JavacReferenceCollectorListener implements TaskListener { private final Map myIncompletelyProcessedFiles = new THashMap(10); static void installOn(JavaCompiler.CompilationTask task, - JavacFileReferencesRegistrar[] fullASTListenerArray, - JavacFileReferencesRegistrar[] onlyImportsListenerArray) { + boolean divideImportRefs, + Consumer dataConsumer) { JavacTask javacTask = (JavacTask)task; Method addTaskMethod = ReflectionUtil.getMethod(JavacTask.class, "addTaskListener", TaskListener.class); // jdk >= 8 - final JavacReferenceCollectorListener taskListener = new JavacReferenceCollectorListener(fullASTListenerArray, onlyImportsListenerArray); + final JavacReferenceCollectorListener taskListener = new JavacReferenceCollectorListener(divideImportRefs, dataConsumer); if (addTaskMethod != null) { try { addTaskMethod.invoke(task, taskListener); @@ -71,9 +69,9 @@ final class JavacReferenceCollectorListener implements TaskListener { } } - private JavacReferenceCollectorListener(JavacFileReferencesRegistrar[] fullASTListenerArray, JavacFileReferencesRegistrar[] importsListenerArray) { - myFullASTListeners = fullASTListenerArray; - myOnlyImportsListeners = importsListenerArray; + private JavacReferenceCollectorListener(boolean divideImportRefs, Consumer dataConsumer) { + myDivideImportRefs = divideImportRefs; + myDataConsumer = dataConsumer; myAstScanner = JavacTreeRefScanner.createASTScanner(); } @@ -93,37 +91,32 @@ final class JavacReferenceCollectorListener implements TaskListener { final int size = declarations.size(); boolean isFileDataComplete = true; - boolean submitImportsOnlyData = true; + boolean collectImportsData = true; JCTree declarationToProcess = null; - final Set collectedReferences; - final List collectedDefinitions; final TypeElement analyzedElement = e.getTypeElement(); + IncompletelyProcessedFile incompletelyProcessedFile; switch (size) { case 0: - collectedReferences = IncompletelyProcessedFile.createReferenceHolder(); - collectedDefinitions = IncompletelyProcessedFile.createDefinitionHolder(); + incompletelyProcessedFile = new IncompletelyProcessedFile(0, fileName); break; case 1: - collectedReferences = IncompletelyProcessedFile.createReferenceHolder(); - collectedDefinitions = IncompletelyProcessedFile.createDefinitionHolder(); + incompletelyProcessedFile = new IncompletelyProcessedFile(0, fileName); declarationToProcess = declarations.get(0); break; default: - IncompletelyProcessedFile incompletelyProcessedFile = myIncompletelyProcessedFiles.get(fileName); + incompletelyProcessedFile = myIncompletelyProcessedFiles.get(fileName); if (incompletelyProcessedFile == null) { - myIncompletelyProcessedFiles.put(fileName, incompletelyProcessedFile = new IncompletelyProcessedFile(size)); + myIncompletelyProcessedFiles.put(fileName, incompletelyProcessedFile = new IncompletelyProcessedFile(size, fileName)); } else { - submitImportsOnlyData = false; + collectImportsData = false; } - if (--incompletelyProcessedFile.remainDeclarations == 0) { + if (incompletelyProcessedFile.decrementRemainDeclarationsAndGet() == 0) { myIncompletelyProcessedFiles.remove(fileName); } else { isFileDataComplete = false; } - collectedReferences = incompletelyProcessedFile.collectedReferences; - collectedDefinitions = incompletelyProcessedFile.collectedDefinitions; for (JCTree declaration : declarations) { if (declaration.type != null && declaration.type.tsym == analyzedElement) { @@ -135,22 +128,22 @@ final class JavacReferenceCollectorListener implements TaskListener { if (declarationToProcess == null) throw new IllegalStateException("Can't find tree for " + analyzedElement.getQualifiedName()); } - if (submitImportsOnlyData) { - scanImports(unit, collectedReferences); - for (JavacFileReferencesRegistrar r : myOnlyImportsListeners) { - r.registerFile(fileName, collectedReferences, collectedDefinitions); + if (collectImportsData) { + scanImports(unit, incompletelyProcessedFile.myFileData.getRefs()); + if (myDivideImportRefs) { + scanImports(unit, incompletelyProcessedFile.myFileData.getImportRefs()); } } - if (myFullASTListeners.length == 0) return; + final IncompletelyProcessedFile finalIncompletelyProcessedFile = incompletelyProcessedFile; JavacTreeScannerSink sink = new JavacTreeScannerSink() { @Override public void sinkReference(JavacRef.JavacSymbolRefBase ref) { - collectedReferences.add(ref); + finalIncompletelyProcessedFile.myFileData.getRefs().add(ref); } @Override public void sinkDeclaration(JavacDef def) { - collectedDefinitions.add(def); + finalIncompletelyProcessedFile.myFileData.getDefs().add(def); } }; myAstScanner.scan(declarationToProcess, sink); @@ -160,9 +153,7 @@ final class JavacReferenceCollectorListener implements TaskListener { myAstScanner.scan(annotation, sink); } - for (JavacFileReferencesRegistrar r : myFullASTListeners) { - r.registerFile(e.getSourceFile().getName(), collectedReferences, collectedDefinitions); - } + myDataConsumer.consume(incompletelyProcessedFile.myFileData); } } } @@ -178,7 +169,7 @@ final class JavacReferenceCollectorListener implements TaskListener { return myAsterisk; } - private void scanImports(JCTree.JCCompilationUnit compilationUnit, Set symbols) { + private void scanImports(JCTree.JCCompilationUnit compilationUnit, Collection symbols) { for (JCTree.JCImport anImport : compilationUnit.getImports()) { final JCTree.JCFieldAccess id = (JCTree.JCFieldAccess)anImport.getQualifiedIdentifier(); final Symbol sym = id.sym; @@ -205,7 +196,7 @@ final class JavacReferenceCollectorListener implements TaskListener { } } - private static void collectClassImports(Symbol baseImport, Set collector) { + private static void collectClassImports(Symbol baseImport, Collection collector) { for (Symbol symbol = baseImport; symbol != null && symbol.getKind() != ElementKind.PACKAGE; symbol = symbol.owner) { @@ -213,31 +204,38 @@ final class JavacReferenceCollectorListener implements TaskListener { } } - private static class IncompletelyProcessedFile { - private final Set collectedReferences = createReferenceHolder(); - private final List collectedDefinitions = createDefinitionHolder(); - private int remainDeclarations; + private class IncompletelyProcessedFile { + private final JavacFileData myFileData; + private int myRemainDeclarations; - private IncompletelyProcessedFile(int remainDeclarations) { - this.remainDeclarations = remainDeclarations; + private IncompletelyProcessedFile(int remainDeclarations, String filePath) { + myRemainDeclarations = remainDeclarations; + myFileData = new JavacFileData(filePath, + createReferenceHolder(), + myDivideImportRefs ? createReferenceHolder() : Collections.emptyList(), + createDefinitionHolder()); } - private static Set createReferenceHolder() { - return new THashSet(new TObjectHashingStrategy() { - @Override - public int computeHashCode(JavacRef.JavacSymbolRefBase ref) { - return ref.getOriginalElement().hashCode(); - } - - @Override - public boolean equals(JavacRef.JavacSymbolRefBase r1, JavacRef.JavacSymbolRefBase r2) { - return r1.getOriginalElement() == r2.getOriginalElement(); - } - }); - } - - private static List createDefinitionHolder() { - return new ArrayList(); + private int decrementRemainDeclarationsAndGet() { + return --myRemainDeclarations; } } + + private static Set createReferenceHolder() { + return new THashSet(new TObjectHashingStrategy() { + @Override + public int computeHashCode(JavacRef ref) { + return ((JavacRef.JavacSymbolRefBase) ref).getOriginalElement().hashCode(); + } + + @Override + public boolean equals(JavacRef r1, JavacRef r2) { + return ((JavacRef.JavacSymbolRefBase) r1).getOriginalElement() == ((JavacRef.JavacSymbolRefBase) r2).getOriginalElement(); + } + }); + } + + private static List createDefinitionHolder() { + return new ArrayList(); + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java index 7830dd894fa5..f61438b4fcab 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java @@ -15,34 +15,19 @@ */ package org.jetbrains.jps.javac.ast; -import com.intellij.util.SmartList; -import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar; -import org.jetbrains.jps.service.JpsServiceManager; +import com.intellij.util.Consumer; +import org.jetbrains.jps.javac.ast.api.JavacFileData; import javax.tools.*; -import java.util.List; /** * Code here should not depend on any javac private API located in tools.jar if no JavacFileReferencesRegistrar-s will be run. * A workaround to allow run standalone jps with improperly configured classloader without NoClassDefFoundError (e.g: IDEA-162877) */ public class JavacReferencesCollector { - public static void installOn(JavaCompiler.CompilationTask task) { - List fullASTListeners = new SmartList(); - List onlyImportsListeners = new SmartList(); - for (JavacFileReferencesRegistrar listener : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) { - if (!listener.initialize()) { - continue; - } - (listener.onlyImports() ? onlyImportsListeners : fullASTListeners).add(listener); - } - - final JavacFileReferencesRegistrar[] fullASTListenerArray = fullASTListeners.toArray(new JavacFileReferencesRegistrar[fullASTListeners.size()]); - final JavacFileReferencesRegistrar[] onlyImportsListenerArray = onlyImportsListeners.toArray(new JavacFileReferencesRegistrar[onlyImportsListeners.size()]); - if (fullASTListenerArray.length == 0 && onlyImportsListenerArray.length == 0) { - return; - } - - JavacReferenceCollectorListener.installOn(task, fullASTListenerArray, onlyImportsListenerArray); + public static void installOn(JavaCompiler.CompilationTask task, + boolean divideImportRefs, + Consumer fileDataConsumer) { + JavacReferenceCollectorListener.installOn(task, divideImportRefs, fileDataConsumer); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/RefCollectorCompilerToolExtension.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/RefCollectorCompilerToolExtension.java index e45c0dd9021a..ee37c8d88400 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/RefCollectorCompilerToolExtension.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/RefCollectorCompilerToolExtension.java @@ -15,14 +15,23 @@ */ package org.jetbrains.jps.javac.ast; +import com.intellij.openapi.util.AtomicClearableLazyValue; +import com.intellij.util.Consumer; +import com.intellij.util.SystemProperties; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; import org.jetbrains.jps.builders.java.JavaCompilingTool; import org.jetbrains.jps.javac.DiagnosticOutputConsumer; import org.jetbrains.jps.javac.JavaCompilerToolExtension; +import org.jetbrains.jps.javac.ast.api.JavacFileData; +import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar; import org.jetbrains.jps.model.java.compiler.JavaCompilers; +import org.jetbrains.jps.service.JpsServiceManager; import javax.tools.*; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** * @author Eugene Zhuravlev @@ -31,6 +40,24 @@ import java.util.Collection; public class RefCollectorCompilerToolExtension extends JavaCompilerToolExtension{ public static final String ID = "ASTReferenceCollector"; + private static final String ENABLED_PARAM = "jps.ref.collector.enabled"; + private static final String DIVIDE_IMPORTS_PARAM = "jps.divide.imports"; + + private final AtomicClearableLazyValue> myRegistrars = new AtomicClearableLazyValue>() { + @NotNull + @Override + protected List compute() { + List result = new ArrayList(); + for (JavacFileReferencesRegistrar registrar : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) { + if (registrar.isEnabled()) { + registrar.initialize(); + result.add(registrar); + } + } + return result; + } + }; + @NotNull @Override public String getId() { @@ -41,15 +68,94 @@ public class RefCollectorCompilerToolExtension extends JavaCompilerToolExtension public void beforeCompileTaskExecution(@NotNull JavaCompilingTool compilingTool, @NotNull JavaCompiler.CompilationTask task, @NotNull Collection options, - @NotNull DiagnosticOutputConsumer diagnosticConsumer) { - // todo: transfer collected data via DiagnosticOutputConsumer.customOutputData() - if (JavaCompilers.JAVAC_ID.equals(compilingTool.getId())) { - JavacReferencesCollector.installOn(task); + @NotNull final DiagnosticOutputConsumer diagnosticConsumer) { + if (isJavac(compilingTool)) { + final String isEnabledProperty = System.getProperty(ENABLED_PARAM); + + Consumer fileDataConsumer; + boolean divideImportsRefs; + if (isEnabledProperty == null) { + //in-process + final RefCollectorOptions refCollectorOptions = new RefCollectorOptions(); + fileDataConsumer = refCollectorOptions.enabled ? new Consumer() { + @Override + public void consume(JavacFileData data) { + submitFileData(data); + } + } : null; + divideImportsRefs = refCollectorOptions.divideImportRefs; + } else if (isEnabledProperty.equals("true")) { + //external + fileDataConsumer = new Consumer() { + @Override + public void consume(JavacFileData data) { + diagnosticConsumer.customOutputData(ID, "javac-refs", data.asBytes()); + } + }; + divideImportsRefs = SystemProperties.getBooleanProperty(DIVIDE_IMPORTS_PARAM, false); + } else { + return; + } + + if (fileDataConsumer != null) { + JavacReferencesCollector.installOn(task, divideImportsRefs, fileDataConsumer); + } } } + @Override + public List getExternalBuildProcessOptions(@NotNull JavaCompilingTool compilingTool) { + List options = new ArrayList(2); + if (isJavac(compilingTool)) { + final RefCollectorOptions refCollectorOptions = new RefCollectorOptions(); + options.add("-D" + ENABLED_PARAM + "=" + refCollectorOptions.enabled); + if (refCollectorOptions.enabled && refCollectorOptions.divideImportRefs) { + options.add("-D" + DIVIDE_IMPORTS_PARAM + "=true"); + } + } else { + options.add("-D" + ENABLED_PARAM + "=false"); + } + return options; + } + @Override public void processData(String dataName, byte[] content) { - // todo! + submitFileData(JavacFileData.fromBytes(content)); + } + + private void submitFileData(@NotNull JavacFileData data) { + for (JavacFileReferencesRegistrar registrar : myRegistrars.getValue()) { + registrar.registerFile(data.getFilePath(), registrar.onlyImports() ? data.getImportRefs() : data.getRefs(), data.getDefs()); + } + } + + private static boolean isJavac(@NotNull JavaCompilingTool compilingTool) { + return JavaCompilers.JAVAC_ID.equals(compilingTool.getId()); + } + + private static class RefCollectorOptions { + private final boolean enabled; + private final boolean divideImportRefs; + + private RefCollectorOptions() { + boolean enabled = false; + boolean divideImportRefs = false; + for (JavacFileReferencesRegistrar listener : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) { + if (listener.isEnabled()) { + enabled = true; + if (listener.onlyImports()) { + divideImportRefs = true; + } + } + } + + this.enabled = enabled; + this.divideImportRefs = divideImportRefs; + } + } + + @TestOnly + public void clearRegistrars() { + myRegistrars.drop(); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileData.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileData.java new file mode 100644 index 000000000000..364cf25b0b85 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileData.java @@ -0,0 +1,247 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.jps.javac.ast.api; + +import com.intellij.openapi.util.ThrowableComputable; +import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; +import com.intellij.util.ThrowableConsumer; +import com.intellij.util.io.*; +import com.intellij.util.io.DataOutputStream; +import org.jetbrains.annotations.NotNull; + +import java.io.*; +import java.util.Collection; +import java.util.List; + +public class JavacFileData { + private final String myFilePath; + private final Collection myRefs; + private final Collection myImportRefs; + private final List myDefs; + + public JavacFileData(@NotNull String path, + @NotNull Collection refs, + @NotNull Collection importRefs, + @NotNull List defs) { + myFilePath = path; + myRefs = refs; + myImportRefs = importRefs; + myDefs = defs; + } + + @NotNull + public String getFilePath() { + return myFilePath; + } + + @NotNull + public Collection getRefs() { + return myRefs; + } + + @NotNull + public Collection getImportRefs() { + return myImportRefs; + } + + @NotNull + public List getDefs() { + return myDefs; + } + + @NotNull + public byte[] asBytes() { + final BufferExposingByteArrayOutputStream os = new BufferExposingByteArrayOutputStream(); + DataOutputStream stream = new DataOutputStream(os); + try { + EXTERNALIZER.save(stream, this); + } + catch (IOException e) { + throw new RuntimeException(e); + } + return os.toByteArray(); + } + + @NotNull + public static JavacFileData fromBytes(byte[] bytes) { + final UnsyncByteArrayInputStream is = new UnsyncByteArrayInputStream(bytes); + try { + return EXTERNALIZER.read(new DataInputStream(is)); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static final DataExternalizer EXTERNALIZER = new DataExternalizer() { + DataExternalizer myRefSeqExternalizer = createRefExternalizer(); + DataExternalizer myDefSeqExternalizer = createDefExternalizer(); + + @Override + public void save(@NotNull DataOutput out, JavacFileData data) throws IOException { + EnumeratorStringDescriptor.INSTANCE.save(out, data.getFilePath()); + saveRefs(out, data.getRefs()); + saveRefs(out, data.getImportRefs()); + saveDefs(out, data.getDefs()); + } + + @Override + public JavacFileData read(@NotNull DataInput in) throws IOException { + return new JavacFileData(EnumeratorStringDescriptor.INSTANCE.read(in), + readRefs(in), + readRefs(in), + readDefs(in)); + } + + + private void saveRefs(final DataOutput out, Collection refs) throws IOException { + DataInputOutputUtil.writeSeq(out, refs, new ThrowableConsumer() { + @Override + public void consume(JavacRef ref) throws IOException { + myRefSeqExternalizer.save(out, ref); + } + }); + } + + private Collection readRefs(final DataInput in) throws IOException { + return DataInputOutputUtil.readSeq(in, new ThrowableComputable() { + @Override + public JavacRef compute() throws IOException { + return myRefSeqExternalizer.read(in); + } + }); + } + + private void saveDefs(final DataOutput out, List defs) throws IOException { + DataInputOutputUtil.writeSeq(out, defs, new ThrowableConsumer() { + @Override + public void consume(JavacDef def) throws IOException { + myDefSeqExternalizer.save(out, def); + } + }); + } + + private List readDefs(final DataInput in) throws IOException { + return DataInputOutputUtil.readSeq(in, new ThrowableComputable() { + @Override + public JavacDef compute() throws IOException { + return myDefSeqExternalizer.read(in); + } + }); + } + + }; + + private static DataExternalizer createDefExternalizer() { + return new DataExternalizer() { + private static final byte CLASS_MARKER = 0; + private static final byte FUN_EXPR_MARKER = 1; + + DataExternalizer refExternalizer = createRefExternalizer(); + + @Override + public void save(@NotNull DataOutput out, JavacDef def) throws IOException { + if (def instanceof JavacDef.JavacClassDef) { + out.writeByte(CLASS_MARKER); + final JavacRef[] superClasses = ((JavacDef.JavacClassDef)def).getSuperClasses(); + out.writeInt(superClasses.length); + for (JavacRef aClass : superClasses) { + refExternalizer.save(out, aClass); + } + } + else if (def instanceof JavacDef.JavacFunExprDef) { + out.writeByte(FUN_EXPR_MARKER); + } else { + throw new IllegalStateException("unknown type: " + def.getClass()); + } + refExternalizer.save(out, def.getDefinedElement()); + } + + @Override + public JavacDef read(@NotNull DataInput in) throws IOException { + final byte marker = in.readByte(); + switch (marker) { + case CLASS_MARKER: + final int supersSize = in.readInt(); + JavacRef[] superClasses = new JavacRef[supersSize]; + for (int i = 0; i < supersSize; i++) { + superClasses[i] = refExternalizer.read(in); + } + return new JavacDef.JavacClassDef(refExternalizer.read(in), superClasses); + case FUN_EXPR_MARKER: + return new JavacDef.JavacFunExprDef(refExternalizer.read(in)); + default: throw new IllegalStateException("unknown marker " + marker); + } + } + }; + } + + private static DataExternalizer createRefExternalizer() { + return new DataExternalizer() { + private static final byte CLASS_MARKER = 0; + private static final byte METHOD_MARKER = 1; + private static final byte FIELD_MARKER = 2; + + @Override + public void save(@NotNull DataOutput out, JavacRef ref) throws IOException { + if (ref instanceof JavacRef.JavacClass) { + out.writeByte(CLASS_MARKER); + out.writeBoolean(((JavacRef.JavacClass)ref).isAnonymous()); + } + else if (ref instanceof JavacRef.JavacField) { + out.writeByte(FIELD_MARKER); + writeBytes(out, ref.getOwnerName()); + } + else if (ref instanceof JavacRef.JavacMethod) { + out.writeByte(METHOD_MARKER); + writeBytes(out, ref.getOwnerName()); + out.write(((JavacRef.JavacMethod)ref).getParamCount()); + } else { + throw new IllegalStateException("unknown type: " + ref.getClass()); + } + out.writeLong(ref.getFlags()); + writeBytes(out, ref.getName()); + } + + @Override + public JavacRef read(@NotNull DataInput in) throws IOException { + final byte marker = in.readByte(); + switch (marker) { + case CLASS_MARKER: + return new JavacRef.JavacClassImpl(in.readBoolean(), in.readLong(), readBytes(in)); + case METHOD_MARKER: + return new JavacRef.JavacMethodImpl(readBytes(in), in.readByte(), in.readLong(), readBytes(in)); + case FIELD_MARKER: + return new JavacRef.JavacFieldImpl(readBytes(in), in.readLong(), readBytes(in)); + default: + throw new IllegalStateException("unknown marker " + marker); + } + } + + private void writeBytes(DataOutput out, byte[] bytes) throws IOException { + out.writeInt(bytes.length); + out.write(bytes); + } + + private byte[] readBytes(DataInput in) throws IOException { + final int len = in.readInt(); + final byte[] buf = new byte[len]; + in.readFully(buf); + return buf; + } + }; + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java index e5106fd5a223..7ac2534c95fd 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java @@ -15,14 +15,15 @@ */ package org.jetbrains.jps.javac.ast.api; +import java.util.Collection; import java.util.List; -import java.util.Set; public interface JavacFileReferencesRegistrar { + void initialize(); - boolean initialize(); + boolean isEnabled(); boolean onlyImports(); - void registerFile(String filePath, Set refs, List defs); + void registerFile(String filePath, Collection refs, List defs); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacRef.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacRef.java index ed141386cd09..a7c532cfb3dc 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacRef.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacRef.java @@ -16,6 +16,7 @@ package org.jetbrains.jps.javac.ast.api; import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.util.Convert; import org.jetbrains.annotations.NotNull; public interface JavacRef { @@ -64,7 +65,7 @@ public interface JavacRef { class JavacClassImpl extends JavacRefBase implements JavacClass { private boolean myAnonymous; - public JavacClassImpl(byte[] name, long flags, boolean anonymous) { + public JavacClassImpl(boolean anonymous, long flags, byte[] name) { super(name, flags); myAnonymous = anonymous; } @@ -78,13 +79,18 @@ public interface JavacRef { public boolean isAnonymous() { return myAnonymous; } + + @Override + public String toString() { + return Convert.utf2string(getName()); + } } class JavacMethodImpl extends JavacRefBase implements JavacMethod { private final byte[] myOwnerName; private final byte myParamCount; - public JavacMethodImpl(byte[] name, byte[] ownerName, byte paramCount, long flags) { + public JavacMethodImpl(byte[] ownerName, byte paramCount, long flags, byte[] name) { super(name, flags); myOwnerName = ownerName; myParamCount = paramCount; @@ -99,12 +105,17 @@ public interface JavacRef { public byte[] getOwnerName() { return myOwnerName; } + + @Override + public String toString() { + return Convert.utf2string(getOwnerName()) + "." + Convert.utf2string(getName()) + "(" + myParamCount + ")"; + } } class JavacFieldImpl extends JavacRefBase implements JavacField { private final byte[] myOwnerName; - public JavacFieldImpl(byte[] name, byte[] ownerName, long flags) { + public JavacFieldImpl(byte[] ownerName, long flags, byte[] name) { super(name, flags); myOwnerName = ownerName; } @@ -114,6 +125,11 @@ public interface JavacRef { public byte[] getOwnerName() { return myOwnerName; } + + @Override + public String toString() { + return Convert.utf2string(getOwnerName()) + "." + Convert.utf2string(getName()); + } } abstract class JavacSymbolRefBase implements JavacRef { diff --git a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt index 602b49de9f8e..131d2c7776a3 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt +++ b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt @@ -29,9 +29,12 @@ import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex import org.jetbrains.jps.backwardRefs.LightRef import org.jetbrains.jps.backwardRefs.index.CompiledFileData import org.jetbrains.jps.backwardRefs.index.CompilerIndices +import org.jetbrains.jps.builders.BuildResult import org.jetbrains.jps.builders.JpsBuildTestCase import org.jetbrains.jps.builders.TestProjectBuilderLogger import org.jetbrains.jps.builders.logging.BuildLoggingManager +import org.jetbrains.jps.javac.JavaCompilerToolExtension +import org.jetbrains.jps.javac.ast.RefCollectorCompilerToolExtension import java.io.File abstract class ReferenceIndexTestBase : JpsBuildTestCase() { @@ -58,6 +61,22 @@ abstract class ReferenceIndexTestBase : JpsBuildTestCase() { assertIndexEquals("initialIndex.txt") } + override fun rebuildAllModules() { + try { + super.rebuildAllModules() + } finally { + (JavaCompilerToolExtension.getExtension(RefCollectorCompilerToolExtension.ID) as RefCollectorCompilerToolExtension).clearRegistrars() + } + } + + override fun buildAllModules(): BuildResult { + try { + return super.buildAllModules() + } finally { + (JavaCompilerToolExtension.getExtension(RefCollectorCompilerToolExtension.ID) as RefCollectorCompilerToolExtension).clearRegistrars() + } + } + protected fun renameFile(fileToRename: String, newName: String) { rename(orCreateProjectDir.path + "/m/" + fileToRename, newName) } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/CustomFileDropHandler.java b/platform/platform-impl/src/com/intellij/openapi/editor/CustomFileDropHandler.java index 27090bdeb11a..600ec36b195c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/CustomFileDropHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/CustomFileDropHandler.java @@ -18,6 +18,7 @@ package com.intellij.openapi.editor; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.awt.datatransfer.Transferable; @@ -25,7 +26,7 @@ public abstract class CustomFileDropHandler { public static final ExtensionPointName CUSTOM_DROP_HANDLER_EP = ExtensionPointName.create("com.intellij.customFileDropHandler"); - public abstract boolean canHandle(@NotNull Transferable t, Editor editor); + public abstract boolean canHandle(@NotNull Transferable t, @Nullable Editor editor); - public abstract boolean handleDrop(@NotNull Transferable t, Editor editor, final Project project); + public abstract boolean handleDrop(@NotNull Transferable t, @Nullable Editor editor, final Project project); } diff --git a/platform/platform-resources/src/fonts/FiraCode-Bold.ttf b/platform/platform-resources/src/fonts/FiraCode-Bold.ttf index 04cd794d4ee6..b919d6b711f1 100644 Binary files a/platform/platform-resources/src/fonts/FiraCode-Bold.ttf and b/platform/platform-resources/src/fonts/FiraCode-Bold.ttf differ diff --git a/platform/platform-resources/src/fonts/FiraCode-Light.ttf b/platform/platform-resources/src/fonts/FiraCode-Light.ttf index 33bf04fbb037..50fe033b02cf 100644 Binary files a/platform/platform-resources/src/fonts/FiraCode-Light.ttf and b/platform/platform-resources/src/fonts/FiraCode-Light.ttf differ diff --git a/platform/platform-resources/src/fonts/FiraCode-Medium.ttf b/platform/platform-resources/src/fonts/FiraCode-Medium.ttf index 8b113f1c2e7f..88a675052398 100644 Binary files a/platform/platform-resources/src/fonts/FiraCode-Medium.ttf and b/platform/platform-resources/src/fonts/FiraCode-Medium.ttf differ diff --git a/platform/platform-resources/src/fonts/FiraCode-Regular.ttf b/platform/platform-resources/src/fonts/FiraCode-Regular.ttf index d96a62a0cb27..575c21ba7ec5 100644 Binary files a/platform/platform-resources/src/fonts/FiraCode-Regular.ttf and b/platform/platform-resources/src/fonts/FiraCode-Regular.ttf differ diff --git a/platform/platform-resources/src/fonts/FiraCode-Retina.ttf b/platform/platform-resources/src/fonts/FiraCode-Retina.ttf index 3ff4026be699..95fbbc659584 100644 Binary files a/platform/platform-resources/src/fonts/FiraCode-Retina.ttf and b/platform/platform-resources/src/fonts/FiraCode-Retina.ttf differ diff --git a/platform/util/src/com/intellij/openapi/util/SystemInfo.java b/platform/util/src/com/intellij/openapi/util/SystemInfo.java index 852b5240cdb5..7629801f9df7 100644 --- a/platform/util/src/com/intellij/openapi/util/SystemInfo.java +++ b/platform/util/src/com/intellij/openapi/util/SystemInfo.java @@ -23,6 +23,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.List; @@ -57,12 +58,49 @@ public class SystemInfo extends SystemInfoRt { } // version numbers from http://msdn.microsoft.com/en-us/library/windows/desktop/ms724832.aspx + public static final boolean isWin10OrNewer = isWindows && isOsVersionAtLeast("10.0"); public static final boolean isWin2kOrNewer = isWindows && isOsVersionAtLeast("5.0"); public static final boolean isWinXpOrNewer = isWindows && isOsVersionAtLeast("5.1"); public static final boolean isWinVistaOrNewer = isWindows && isOsVersionAtLeast("6.0"); public static final boolean isWin7OrNewer = isWindows && isOsVersionAtLeast("6.1"); public static final boolean isWin8OrNewer = isWindows && isOsVersionAtLeast("6.2"); + /** + * https://msdn.microsoft.com/en-us/commandline/wsl/about + */ + private static final AtomicNullableLazyValue ourWSLBashFile = new AtomicNullableLazyValue() { + @Nullable + @Override + protected File compute() { + if (!isWin10OrNewer) { + return null; + } + + String windir = System.getenv().get("windir"); + if (StringUtil.isEmpty(windir)) { + return null; + } + + return new File(windir + "\\System32\\bash.exe"); + } + }; + + /** + * @return WSL bash file or null if unavailable + */ + @Nullable + public static File getWSLBashFile() { + File bashFile = ourWSLBashFile.getValue(); + return bashFile == null || !bashFile.exists() ? null : bashFile; + } + + /** + * @return true if we are on Windows 10+ and have WSL installed + */ + public static boolean hasWSL() { + return getWSLBashFile() != null; + } + public static final boolean isXWindow = isUnix && !isMac; // https://userbase.kde.org/KDE_System_Administration/Environment_Variables#KDE_FULL_SESSION public static final boolean isKDE = !StringUtil.isEmpty(System.getenv("KDE_FULL_SESSION")); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchFileDropHandler.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchFileDropHandler.java index f27486b0309b..99fe2d6f919c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchFileDropHandler.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchFileDropHandler.java @@ -20,6 +20,7 @@ import com.intellij.openapi.editor.CustomFileDropHandler; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.awt.datatransfer.Transferable; import java.io.File; @@ -28,14 +29,14 @@ import java.util.List; public class PatchFileDropHandler extends CustomFileDropHandler { @Override - public boolean canHandle(@NotNull Transferable t, Editor editor) { + public boolean canHandle(@NotNull Transferable t, @Nullable Editor editor) { List list = FileCopyPasteUtil.getFileList(t); if (list == null || list.size() != 1) return false; return PatchFileType.isPatchFile(list.get(0)); } @Override - public boolean handleDrop(@NotNull Transferable t, Editor editor, @NotNull final Project project) { + public boolean handleDrop(@NotNull Transferable t, @Nullable Editor editor, @NotNull final Project project) { List list = FileCopyPasteUtil.getFileList(t); if (list == null || list.size() != 1) return false; return ApplyPatchAction.showAndGetApplyPatch(project, list.get(0)); diff --git a/plugins/devkit/src/inspections/quickfix/AbstractRegisterFix.java b/plugins/devkit/src/inspections/quickfix/AbstractRegisterFix.java index dc7f8ef7ba5d..740c956c14cd 100644 --- a/plugins/devkit/src/inspections/quickfix/AbstractRegisterFix.java +++ b/plugins/devkit/src/inspections/quickfix/AbstractRegisterFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.text.StringUtil; @@ -43,7 +43,7 @@ abstract class AbstractRegisterFix implements LocalQuickFix, DescriptorUtil.Patc protected final SmartPsiElementPointer myPointer; protected static final Logger LOG = Logger.getInstance(AbstractRegisterFix.class); - public AbstractRegisterFix(@NotNull SmartPsiElementPointer klass) { + protected AbstractRegisterFix(@NotNull SmartPsiElementPointer klass) { myPointer = klass; } @@ -52,6 +52,11 @@ abstract class AbstractRegisterFix implements LocalQuickFix, DescriptorUtil.Patc return DevKitBundle.message("inspections.component.not.registered.quickfix.family"); } + @Override + public boolean startInWriteAction() { + return false; + } + @NotNull public String getName() { return DevKitBundle.message("inspections.component.not.registered.quickfix.name", getType()); @@ -76,7 +81,7 @@ abstract class AbstractRegisterFix implements LocalQuickFix, DescriptorUtil.Patc return; } LOG.assertTrue(psiFile != null); - final Module module = ModuleUtil.findModuleForFile(psiFile.getVirtualFile(), project); + final Module module = ModuleUtilCore.findModuleForFile(psiFile.getVirtualFile(), project); assert module != null; Runnable command = () -> { diff --git a/plugins/devkit/src/util/DescriptorUtil.java b/plugins/devkit/src/util/DescriptorUtil.java index feb3fa2f4c39..57b8b2e876ea 100644 --- a/plugins/devkit/src/util/DescriptorUtil.java +++ b/plugins/devkit/src/util/DescriptorUtil.java @@ -15,6 +15,7 @@ */ package org.jetbrains.idea.devkit.util; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.module.Module; import com.intellij.openapi.vfs.ReadonlyStatusHandler; import com.intellij.openapi.vfs.VirtualFile; @@ -23,6 +24,7 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ThrowableRunnable; import com.intellij.util.xml.DomFileElement; import com.intellij.util.xml.DomManager; import org.jetbrains.annotations.NotNull; @@ -67,9 +69,11 @@ public class DescriptorUtil { throw new IncorrectOperationException(DevKitBundle.message("error.plugin.xml.readonly")); } - for (XmlFile pluginXml : pluginXmls) { - patcher.patchPluginXml(pluginXml, klass); - } + WriteAction.run((ThrowableRunnable)() -> { + for (XmlFile pluginXml : pluginXmls) { + patcher.patchPluginXml(pluginXml, klass); + } + }); } @Nullable diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/settings/CCOptions.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/settings/CCOptions.java index 4ebd48652970..4835ad525e01 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/settings/CCOptions.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/settings/CCOptions.java @@ -5,31 +5,11 @@ import com.jetbrains.edu.learning.settings.StudyOptionsProvider; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; public class CCOptions implements StudyOptionsProvider { private JRadioButton myHtmlRadioButton; private JRadioButton myMarkdownRadioButton; private JPanel myPanel; - private boolean myIsModified = false; - - - public CCOptions() { - myHtmlRadioButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - myIsModified = true; - } - }); - - myMarkdownRadioButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - myIsModified = true; - } - }); - } @Nullable @Override @@ -47,12 +27,15 @@ public class CCOptions implements StudyOptionsProvider { @Override public boolean isModified() { - return myIsModified; + final boolean htmlAsDefaultTaskFormat = CCSettings.getInstance().useHtmlAsDefaultTaskFormat(); + return myHtmlRadioButton.isSelected() != htmlAsDefaultTaskFormat; } @Override public void apply() throws ConfigurationException { - CCSettings.getInstance().setUseHtmlAsDefaultTaskFormat(myHtmlRadioButton.isSelected()); + if (isModified()) { + CCSettings.getInstance().setUseHtmlAsDefaultTaskFormat(myHtmlRadioButton.isSelected()); + } } @Override diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySerializationUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySerializationUtils.java index 279fad1248fc..f4a264d40fff 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySerializationUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySerializationUtils.java @@ -476,23 +476,26 @@ public class StudySerializationUtils { } private static JsonObject convertSubtaskInfosToMap(JsonObject stepOptionsJson) { - for (JsonElement taskFileElement : stepOptionsJson.getAsJsonArray(FILES)) { - JsonObject taskFileObject = taskFileElement.getAsJsonObject(); - JsonArray placeholders = taskFileObject.getAsJsonArray(PLACEHOLDERS); - for (JsonElement placeholder : placeholders) { - JsonObject placeholderObject = placeholder.getAsJsonObject(); - JsonArray infos = placeholderObject.getAsJsonArray(SUBTASK_INFOS); - Map objectsToInsert = new HashMap<>(); - for (JsonElement info : infos) { - JsonObject object = info.getAsJsonObject(); - int index = object.getAsJsonPrimitive(INDEX).getAsInt(); - objectsToInsert.put(index, object); - } - placeholderObject.remove(SUBTASK_INFOS); - JsonObject newInfos = new JsonObject(); - placeholderObject.add(SUBTASK_INFOS, newInfos); - for (Map.Entry entry : objectsToInsert.entrySet()) { - newInfos.add(entry.getKey().toString(), entry.getValue()); + final JsonArray files = stepOptionsJson.getAsJsonArray(FILES); + if (files != null) { + for (JsonElement taskFileElement : files) { + JsonObject taskFileObject = taskFileElement.getAsJsonObject(); + JsonArray placeholders = taskFileObject.getAsJsonArray(PLACEHOLDERS); + for (JsonElement placeholder : placeholders) { + JsonObject placeholderObject = placeholder.getAsJsonObject(); + JsonArray infos = placeholderObject.getAsJsonArray(SUBTASK_INFOS); + Map objectsToInsert = new HashMap<>(); + for (JsonElement info : infos) { + JsonObject object = info.getAsJsonObject(); + int index = object.getAsJsonPrimitive(INDEX).getAsInt(); + objectsToInsert.put(index, object); + } + placeholderObject.remove(SUBTASK_INFOS); + JsonObject newInfos = new JsonObject(); + placeholderObject.add(SUBTASK_INFOS, newInfos); + for (Map.Entry entry : objectsToInsert.entrySet()) { + newInfos.add(entry.getKey().toString(), entry.getValue()); + } } } } @@ -501,14 +504,17 @@ public class StudySerializationUtils { private static JsonObject convertToSecondVersion(JsonObject stepOptionsJson) { Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); - for (JsonElement taskFileElement : stepOptionsJson.getAsJsonArray(FILES)) { - JsonObject taskFileObject = taskFileElement.getAsJsonObject(); - JsonArray placeholders = taskFileObject.getAsJsonArray(PLACEHOLDERS); - for (JsonElement placeholder : placeholders) { - JsonObject placeholderObject = placeholder.getAsJsonObject(); - convertToAbsoluteOffset(taskFileObject, placeholderObject); - convertMultipleHints(gson, placeholderObject); - convertToSubtaskInfo(placeholderObject); + final JsonArray files = stepOptionsJson.getAsJsonArray(FILES); + if (files != null) { + for (JsonElement taskFileElement : files) { + JsonObject taskFileObject = taskFileElement.getAsJsonObject(); + JsonArray placeholders = taskFileObject.getAsJsonArray(PLACEHOLDERS); + for (JsonElement placeholder : placeholders) { + JsonObject placeholderObject = placeholder.getAsJsonObject(); + convertToAbsoluteOffset(taskFileObject, placeholderObject); + convertMultipleHints(gson, placeholderObject); + convertToSubtaskInfo(placeholderObject); + } } } return stepOptionsJson; diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicAuthorizedClient.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicAuthorizedClient.java index 0760dee299e5..8d36b6626967 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicAuthorizedClient.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicAuthorizedClient.java @@ -182,6 +182,7 @@ public class EduStepicAuthorizedClient { return stepicUser[0]; } + @Nullable public static StepicUser login(@NotNull final String email, @NotNull final String password) { final List parameters = new ArrayList<>(); if (password.isEmpty()) return null; diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicStudyOptions.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicStudyOptions.java index 2e2ac1d8d221..b22afc96329b 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicStudyOptions.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicStudyOptions.java @@ -16,6 +16,8 @@ package com.jetbrains.edu.learning.stepic; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.DocumentAdapter; @@ -27,68 +29,28 @@ 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.event.DocumentListener; import javax.swing.text.Document; import javax.swing.text.PlainDocument; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; public class StepicStudyOptions implements StudyOptionsProvider { - private static final String DEFAULT_PASSWORD_TEXT = "************"; private static final Logger LOG = Logger.getInstance(StepicStudyOptions.class); private JTextField myLoginTextField; private JPasswordField myPasswordField; private JPanel myPane; private JBCheckBox myEnableTestingFromSamples; - private boolean myCredentialsModified; - public StepicStudyOptions() { - myPasswordField.getDocument().addDocumentListener(new DocumentAdapter() { + myLoginTextField.getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { - myCredentialsModified = true; + erasePassword(); } }); - - DocumentListener passwordEraser = new DocumentAdapter() { - @Override - protected void textChanged(DocumentEvent e) { - if (!myCredentialsModified) { - erasePassword(); - } - } - }; - myLoginTextField.getDocument().addDocumentListener(passwordEraser); - - myPasswordField.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - if (!myCredentialsModified && !getPassword().isEmpty()) { - erasePassword(); - } - } - - @Override - public void focusLost(FocusEvent e) { - } - }); - - myEnableTestingFromSamples.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - myCredentialsModified = true; - } - }); - reset(); } private void erasePassword() { setPassword(""); - myCredentialsModified = true; } @NotNull @@ -107,12 +69,15 @@ public class StepicStudyOptions implements StudyOptionsProvider { @NotNull private String getPassword() { - final String passwordText = String.valueOf(myPasswordField.getPassword()); - return passwordText.equals(DEFAULT_PASSWORD_TEXT) ? "" : passwordText; + return String.valueOf(myPasswordField.getPassword()); } private void setPassword(@NotNull final String password) { - myPasswordField.setText(StringUtil.isEmpty(password) ? null : password); + myPasswordField.setText(password); + } + + private boolean isTestingFromSamplesEnabled() { + return myEnableTestingFromSamples.isSelected(); } @Override @@ -122,9 +87,8 @@ public class StepicStudyOptions implements StudyOptionsProvider { StudyTaskManager taskManager = StudyTaskManager.getInstance(project); final StepicUser user = taskManager.getUser(); setLogin(user.getEmail()); - setPassword(DEFAULT_PASSWORD_TEXT); + setPassword(user.getPassword()); myEnableTestingFromSamples.setSelected(taskManager.isEnableTestingFromSamples()); - resetCredentialsModification(); } else { LOG.warn("No study object is opened"); @@ -137,31 +101,42 @@ public class StepicStudyOptions implements StudyOptionsProvider { } @Override - public void apply() { - if (myCredentialsModified) { - final Project project = StudyUtils.getStudyProject(); - if (project != null) { - StudyTaskManager taskManager = StudyTaskManager.getInstance(project); - taskManager.setEnableTestingFromSamples(myEnableTestingFromSamples.isSelected()); + public void apply() throws ConfigurationException { + final Project project = StudyUtils.getStudyProject(); + if (project != null) { + StudyTaskManager taskManager = StudyTaskManager.getInstance(project); + + if (isTestingFromSamplesEnabled() != taskManager.isEnableTestingFromSamples()){ + taskManager.setEnableTestingFromSamples(isTestingFromSamplesEnabled()); + } + + final StepicUser user = taskManager.getUser(); + final boolean isCredentialsModified = !getLogin().equals(user.getEmail()) || !getPassword().equals(user.getPassword()); + if (isCredentialsModified) { final String login = getLogin(); final String password = getPassword(); if (!StringUtil.isEmptyOrSpaces(login) && !StringUtil.isEmptyOrSpaces(password)) { - final StepicUser user = taskManager.getUser(); - user.setEmail(login); - user.setPassword(password); - // login to post credentials - final StepicUser stepicUser = EduStepicAuthorizedClient.login(login, password); - if (stepicUser != null) { - taskManager.setUser(stepicUser); + final StepicUser[] stepicUser = new StepicUser[1]; + ProgressManager.getInstance().runProcessWithProgressSynchronously( + () -> { + ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true); + stepicUser[0] = StudyUtils.execCancelable(() -> EduStepicAuthorizedClient.login(login, password)); + }, "Logging In", true, + project); + + if (stepicUser[0] != null && stepicUser[0].getAccessToken() != null) { + taskManager.setUser(stepicUser[0]); + } + else { + throw new ConfigurationException("Unable to login"); } } } - else { - LOG.warn("No study object is opened"); - } } - resetCredentialsModification(); + else { + LOG.warn("No study object is opened"); + } } @Nullable @@ -171,11 +146,15 @@ public class StepicStudyOptions implements StudyOptionsProvider { } public boolean isModified() { - return myCredentialsModified; - } - - public void resetCredentialsModification() { - myCredentialsModified = false; + final Project project = StudyUtils.getStudyProject(); + if (project == null) return false; + + final StudyTaskManager taskManager = StudyTaskManager.getInstance(project); + final StepicUser user = taskManager.getUser(); + + return !getLogin().equals(user.getEmail()) + || !getPassword().equals(user.getPassword()) + || !isTestingFromSamplesEnabled() == taskManager.isEnableTestingFromSamples(); } private void createUIComponents() {