mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git.labs.intellij.net:idea/community
This commit is contained in:
Generated
+1
@@ -43,6 +43,7 @@
|
||||
<option name="DEPRECATION" value="false" />
|
||||
</component>
|
||||
<component name="JavacSettings">
|
||||
<option name="PREFER_TARGET_JDK_COMPILER" value="false"/>
|
||||
<option name="MAXIMUM_HEAP_SIZE" value="400" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -201,12 +201,12 @@ class _RegExLexer implements FlexLexer {
|
||||
"\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\0\1\115\1\116\1\117\2\72\1\120\1\121\1\122"+
|
||||
"\1\123\1\124\1\125\1\126\1\127\1\0\1\114\1\0"+
|
||||
"\1\130\2\72\1\120\1\131\1\114\1\72\1\120\1\72"+
|
||||
"\1\132\4\72";
|
||||
"\1\123\1\124\1\125\1\126\1\127\1\0\1\130\1\114"+
|
||||
"\1\0\1\131\2\72\1\120\1\132\1\114\1\72\1\120"+
|
||||
"\1\72\1\133\4\72";
|
||||
|
||||
private static int [] zzUnpackAction() {
|
||||
int [] result = new int[144];
|
||||
int [] result = new int[145];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -247,11 +247,12 @@ class _RegExLexer implements FlexLexer {
|
||||
"\0\u041e\0\u041e\0\u041e\0\u0bde\0\u041e\0\u0c1c\0\u041e\0\u0c5a"+
|
||||
"\0\u0c98\0\u0cd6\0\u041e\0\u041e\0\u041e\0\u0d14\0\u0d52\0\u0d90"+
|
||||
"\0\u041e\0\u041e\0\u041e\0\u041e\0\u041e\0\u041e\0\u041e\0\u0dce"+
|
||||
"\0\u0e0c\0\u0e4a\0\u041e\0\u0e88\0\u041e\0\u0ec6\0\u041e\0\u041e"+
|
||||
"\0\u0f04\0\u0f42\0\u0f80\0\u041e\0\u0fbe\0\u0ffc\0\u103a\0\u1078";
|
||||
"\0\u041e\0\u0e0c\0\u0e4a\0\u041e\0\u0e88\0\u041e\0\u0ec6\0\u041e"+
|
||||
"\0\u041e\0\u0f04\0\u0f42\0\u0f80\0\u041e\0\u0fbe\0\u0ffc\0\u103a"+
|
||||
"\0\u1078";
|
||||
|
||||
private static int [] zzUnpackRowMap() {
|
||||
int [] result = new int[144];
|
||||
int [] result = new int[145];
|
||||
int offset = 0;
|
||||
offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -329,29 +330,29 @@ class _RegExLexer implements FlexLexer {
|
||||
"\3\170\5\0\2\170\3\0\1\170\101\0\1\171\1\172"+
|
||||
"\25\0\1\173\144\0\1\174\12\0\1\175\75\0\1\176"+
|
||||
"\1\177\1\0\5\200\1\0\70\200\1\0\2\156\4\0"+
|
||||
"\1\155\7\0\1\156\34\0\1\156\32\0\1\157\66\0"+
|
||||
"\1\201\51\0\1\201\52\0\1\202\45\0\2\203\24\0"+
|
||||
"\2\203\1\0\1\203\4\0\3\203\5\0\2\203\3\0"+
|
||||
"\1\203\22\0\2\204\4\0\1\205\17\0\2\204\1\0"+
|
||||
"\1\204\4\0\3\204\5\0\2\204\3\0\1\204\22\0"+
|
||||
"\2\206\24\0\2\206\1\0\1\206\4\0\3\206\5\0"+
|
||||
"\2\206\3\0\1\206\21\0\5\200\1\207\70\200\2\0"+
|
||||
"\1\210\51\0\1\210\30\0\1\122\67\0\2\211\4\0"+
|
||||
"\1\203\17\0\2\211\1\0\1\211\4\0\3\211\5\0"+
|
||||
"\2\211\3\0\1\211\22\0\2\212\24\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\203\17\0\2\213\1\0\1\213\4\0"+
|
||||
"\3\213\5\0\2\213\3\0\1\213\22\0\2\214\24\0"+
|
||||
"\2\214\1\0\1\214\4\0\3\214\5\0\2\214\3\0"+
|
||||
"\1\214\22\0\2\215\4\0\1\203\17\0\2\215\1\0"+
|
||||
"\1\215\4\0\3\215\5\0\2\215\3\0\1\215\22\0"+
|
||||
"\2\216\4\0\1\203\17\0\2\216\1\0\1\216\4\0"+
|
||||
"\3\216\5\0\2\216\3\0\1\216\22\0\2\217\4\0"+
|
||||
"\1\203\17\0\2\217\1\0\1\217\4\0\3\217\5\0"+
|
||||
"\2\217\3\0\1\217\22\0\2\220\4\0\1\203\17\0"+
|
||||
"\2\220\1\0\1\220\4\0\3\220\5\0\2\220\3\0"+
|
||||
"\1\220\22\0\2\220\4\0\1\205\17\0\2\220\1\0"+
|
||||
"\1\220\4\0\3\220\5\0\2\220\3\0\1\220\21\0";
|
||||
"\1\155\7\0\1\156\34\0\1\156\32\0\1\201\66\0"+
|
||||
"\1\202\51\0\1\202\52\0\1\203\45\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\206\17\0\2\205\1\0"+
|
||||
"\1\205\4\0\3\205\5\0\2\205\3\0\1\205\22\0"+
|
||||
"\2\207\24\0\2\207\1\0\1\207\4\0\3\207\5\0"+
|
||||
"\2\207\3\0\1\207\21\0\5\200\1\210\70\200\2\0"+
|
||||
"\1\211\51\0\1\211\30\0\1\122\67\0\2\212\4\0"+
|
||||
"\1\204\17\0\2\212\1\0\1\212\4\0\3\212\5\0"+
|
||||
"\2\212\3\0\1\212\22\0\2\213\24\0\2\213\1\0"+
|
||||
"\1\213\4\0\3\213\5\0\2\213\3\0\1\213\22\0"+
|
||||
"\2\214\4\0\1\204\17\0\2\214\1\0\1\214\4\0"+
|
||||
"\3\214\5\0\2\214\3\0\1\214\22\0\2\215\24\0"+
|
||||
"\2\215\1\0\1\215\4\0\3\215\5\0\2\215\3\0"+
|
||||
"\1\215\22\0\2\216\4\0\1\204\17\0\2\216\1\0"+
|
||||
"\1\216\4\0\3\216\5\0\2\216\3\0\1\216\22\0"+
|
||||
"\2\217\4\0\1\204\17\0\2\217\1\0\1\217\4\0"+
|
||||
"\3\217\5\0\2\217\3\0\1\217\22\0\2\220\4\0"+
|
||||
"\1\204\17\0\2\220\1\0\1\220\4\0\3\220\5\0"+
|
||||
"\2\220\3\0\1\220\22\0\2\221\4\0\1\204\17\0"+
|
||||
"\2\221\1\0\1\221\4\0\3\221\5\0\2\221\3\0"+
|
||||
"\1\221\22\0\2\221\4\0\1\206\17\0\2\221\1\0"+
|
||||
"\1\221\4\0\3\221\5\0\2\221\3\0\1\221\21\0";
|
||||
|
||||
private static int [] zzUnpackTrans() {
|
||||
int [] result = new int[4278];
|
||||
@@ -399,11 +400,11 @@ class _RegExLexer implements FlexLexer {
|
||||
"\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\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";
|
||||
"\7\11\1\0\1\11\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[144];
|
||||
int [] result = new int[145];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -760,103 +761,104 @@ class _RegExLexer implements FlexLexer {
|
||||
case 1:
|
||||
{ yypopstate(); return RegExpTT.COMMENT;
|
||||
}
|
||||
case 91: break;
|
||||
case 92: break;
|
||||
case 2:
|
||||
{ return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 92: break;
|
||||
case 93: break;
|
||||
case 3:
|
||||
{ return RegExpTT.DOT;
|
||||
}
|
||||
case 93: break;
|
||||
case 94: break;
|
||||
case 4:
|
||||
{ capturingGroupCount++; return RegExpTT.GROUP_BEGIN;
|
||||
}
|
||||
case 94: break;
|
||||
case 95: break;
|
||||
case 5:
|
||||
{ return RegExpTT.GROUP_END;
|
||||
}
|
||||
case 95: break;
|
||||
case 96: break;
|
||||
case 6:
|
||||
{ if (yystate() != CLASS2 && !allowDanglingMetacharacters) { yypushstate(QUANTIFIER); return RegExpTT.LBRACE; } return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 96: break;
|
||||
case 7:
|
||||
{ yypushstate(CLASS2); return RegExpTT.CLASS_BEGIN;
|
||||
}
|
||||
case 97: break;
|
||||
case 7:
|
||||
{ if (yystate() == CLASS2 && !allowNestedCharacterClasses) return RegExpTT.CHARACTER;
|
||||
yypushstate(CLASS2); return RegExpTT.CLASS_BEGIN;
|
||||
}
|
||||
case 98: break;
|
||||
case 8:
|
||||
{ return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN;
|
||||
}
|
||||
case 98: break;
|
||||
case 99: break;
|
||||
case 9:
|
||||
{ return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CHARACTER;
|
||||
}
|
||||
case 99: break;
|
||||
case 100: break;
|
||||
case 10:
|
||||
{ return RegExpTT.CARET;
|
||||
}
|
||||
case 100: break;
|
||||
case 101: break;
|
||||
case 11:
|
||||
{ return RegExpTT.DOLLAR;
|
||||
}
|
||||
case 101: break;
|
||||
case 102: break;
|
||||
case 12:
|
||||
{ return RegExpTT.QUEST;
|
||||
}
|
||||
case 102: break;
|
||||
case 103: break;
|
||||
case 13:
|
||||
{ return RegExpTT.STAR;
|
||||
}
|
||||
case 103: break;
|
||||
case 104: break;
|
||||
case 14:
|
||||
{ return RegExpTT.PLUS;
|
||||
}
|
||||
case 104: break;
|
||||
case 105: break;
|
||||
case 15:
|
||||
{ return RegExpTT.UNION;
|
||||
}
|
||||
case 105: break;
|
||||
case 106: break;
|
||||
case 16:
|
||||
{ return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CTRL_CHARACTER;
|
||||
}
|
||||
case 106: break;
|
||||
case 107: break;
|
||||
case 17:
|
||||
{ if (commentMode) { yypushstate(COMMENT); return RegExpTT.COMMENT; } else return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 107: break;
|
||||
case 108: break;
|
||||
case 18:
|
||||
{ yypopstate(); yypushback(1);
|
||||
}
|
||||
case 108: break;
|
||||
case 109: break;
|
||||
case 19:
|
||||
{ yypopstate(); return RegExpTT.RBRACE;
|
||||
}
|
||||
case 109: break;
|
||||
case 110: break;
|
||||
case 20:
|
||||
{ return RegExpTT.NAME;
|
||||
}
|
||||
case 110: break;
|
||||
case 111: break;
|
||||
case 21:
|
||||
{ return RegExpTT.NUMBER;
|
||||
}
|
||||
case 111: break;
|
||||
case 112: break;
|
||||
case 22:
|
||||
{ return RegExpTT.COMMA;
|
||||
}
|
||||
case 112: break;
|
||||
case 113: break;
|
||||
case 23:
|
||||
{ assert false : yytext();
|
||||
}
|
||||
case 113: break;
|
||||
case 114: break;
|
||||
case 24:
|
||||
{ yybegin(CLASS2); return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 114: break;
|
||||
case 115: break;
|
||||
case 25:
|
||||
{ yybegin(CLASS1); return RegExpTT.CARET;
|
||||
}
|
||||
case 115: break;
|
||||
case 116: break;
|
||||
case 26:
|
||||
{ if (allowNestedCharacterClasses) {
|
||||
yypushstate(CLASS2);
|
||||
@@ -864,85 +866,87 @@ class _RegExLexer implements FlexLexer {
|
||||
}
|
||||
return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 116: break;
|
||||
case 117: break;
|
||||
case 27:
|
||||
{ yypopstate(); return RegExpTT.CLASS_END;
|
||||
}
|
||||
case 117: break;
|
||||
case 118: break;
|
||||
case 28:
|
||||
{ return RegExpTT.MINUS;
|
||||
}
|
||||
case 118: break;
|
||||
case 119: break;
|
||||
case 29:
|
||||
{ return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.ESC_CHARACTER;
|
||||
}
|
||||
case 119: break;
|
||||
case 120: break;
|
||||
case 30:
|
||||
{ yybegin(CLASS2); return RegExpTT.CARET;
|
||||
}
|
||||
case 120: break;
|
||||
case 121: break;
|
||||
case 31:
|
||||
{ yypopstate(); yypushstate(EMBRACED); return RegExpTT.LBRACE;
|
||||
}
|
||||
case 121: break;
|
||||
case 122: break;
|
||||
case 32:
|
||||
{ yypopstate(); return RegExpTT.CATEGORY_SHORT_HAND;
|
||||
}
|
||||
case 122: break;
|
||||
case 123: break;
|
||||
case 33:
|
||||
{ yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER;
|
||||
}
|
||||
case 123: break;
|
||||
case 124: break;
|
||||
case 34:
|
||||
{ yybegin(YYINITIAL); return RegExpTT.GROUP_END;
|
||||
}
|
||||
case 124: break;
|
||||
case 125: break;
|
||||
case 35:
|
||||
{ handleOptions(); return RegExpTT.OPTIONS_ON;
|
||||
}
|
||||
case 125: break;
|
||||
case 126: break;
|
||||
case 36:
|
||||
{ handleOptions(); return RegExpTT.OPTIONS_OFF;
|
||||
}
|
||||
case 126: break;
|
||||
case 127: break;
|
||||
case 37:
|
||||
{ yybegin(YYINITIAL); return RegExpTT.COLON;
|
||||
}
|
||||
case 127: break;
|
||||
case 128: break;
|
||||
case 38:
|
||||
{ yybegin(YYINITIAL); return RegExpTT.GT;
|
||||
}
|
||||
case 128: break;
|
||||
case 129: break;
|
||||
case 39:
|
||||
{ yybegin(YYINITIAL); return RegExpTT.QUOTE;
|
||||
}
|
||||
case 129: break;
|
||||
case 130: break;
|
||||
case 40:
|
||||
{ return RegExpTT.BAD_CHARACTER;
|
||||
}
|
||||
case 130: break;
|
||||
case 131: break;
|
||||
case 41:
|
||||
{ yybegin(OPTIONS); return RegExpTT.SET_OPTIONS;
|
||||
}
|
||||
case 131: break;
|
||||
case 132: break;
|
||||
case 42:
|
||||
// lookahead expression with fixed base length
|
||||
zzMarkedPos = Character.offsetByCodePoints
|
||||
(zzBufferL/*, zzStartRead, zzEndRead - zzStartRead*/, zzStartRead, 1);
|
||||
{ if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(CLASS1); return RegExpTT.CLASS_BEGIN;
|
||||
{ if (yystate() == CLASS2 && !allowNestedCharacterClasses) return RegExpTT.CHARACTER;
|
||||
if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(CLASS1); return RegExpTT.CLASS_BEGIN;
|
||||
}
|
||||
case 132: break;
|
||||
case 133: break;
|
||||
case 43:
|
||||
// lookahead expression with fixed base length
|
||||
zzMarkedPos = Character.offsetByCodePoints
|
||||
(zzBufferL/*, zzStartRead, zzEndRead - zzStartRead*/, zzStartRead, 1);
|
||||
{ yypushstate(NEGATE_CLASS2); return RegExpTT.CLASS_BEGIN;
|
||||
{ if (yystate() == CLASS2 && !allowNestedCharacterClasses) return RegExpTT.CHARACTER;
|
||||
yypushstate(NEGATE_CLASS2); return RegExpTT.CLASS_BEGIN;
|
||||
}
|
||||
case 133: break;
|
||||
case 134: break;
|
||||
case 44:
|
||||
{ return RegExpTT.REDUNDANT_ESCAPE;
|
||||
}
|
||||
case 134: break;
|
||||
case 135: break;
|
||||
case 45:
|
||||
{ if (allowOctalNoLeadingZero) {
|
||||
CharSequence s = yytext();
|
||||
@@ -964,79 +968,79 @@ class _RegExLexer implements FlexLexer {
|
||||
}
|
||||
return RegExpTT.BACKREF;
|
||||
}
|
||||
case 135: break;
|
||||
case 136: break;
|
||||
case 46:
|
||||
{ return (allowOctalNoLeadingZero ? RegExpTT.OCT_CHAR : RegExpTT.BAD_OCT_VALUE);
|
||||
}
|
||||
case 136: break;
|
||||
case 137: break;
|
||||
case 47:
|
||||
{ return (yystate() == CLASS2) ? RegExpTT.REDUNDANT_ESCAPE : RegExpTT.ESC_CHARACTER;
|
||||
}
|
||||
case 137: break;
|
||||
case 138: break;
|
||||
case 48:
|
||||
{ return RegExpTT.ESC_CHARACTER;
|
||||
}
|
||||
case 138: break;
|
||||
case 139: break;
|
||||
case 49:
|
||||
{ return (yystate() == CLASS2) ? RegExpTT.ESC_CHARACTER : RegExpTT.REDUNDANT_ESCAPE;
|
||||
}
|
||||
case 139: break;
|
||||
case 140: break;
|
||||
case 50:
|
||||
{ return commentMode ? RegExpTT.CHARACTER : RegExpTT.REDUNDANT_ESCAPE;
|
||||
}
|
||||
case 140: break;
|
||||
case 141: break;
|
||||
case 51:
|
||||
{ return RegExpTT.ESC_CTRL_CHARACTER;
|
||||
}
|
||||
case 141: break;
|
||||
case 142: break;
|
||||
case 52:
|
||||
{ return yystate() != CLASS2 ? RegExpTT.BOUNDARY : RegExpTT.ESC_CHARACTER;
|
||||
}
|
||||
case 142: break;
|
||||
case 143: break;
|
||||
case 53:
|
||||
{ return RegExpTT.CHAR_CLASS;
|
||||
}
|
||||
case 143: break;
|
||||
case 144: break;
|
||||
case 54:
|
||||
{ if (xmlSchemaMode) return RegExpTT.CHAR_CLASS; else return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN;
|
||||
}
|
||||
case 144: break;
|
||||
case 145: break;
|
||||
case 55:
|
||||
{ yypushstate(PROP); return RegExpTT.PROPERTY;
|
||||
}
|
||||
case 145: break;
|
||||
case 146: break;
|
||||
case 56:
|
||||
{ return allowTransformationEscapes ? RegExpTT.CHAR_CLASS : StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN;
|
||||
}
|
||||
case 146: break;
|
||||
case 147: break;
|
||||
case 57:
|
||||
{ yypushstate(QUOTED); return RegExpTT.QUOTE_BEGIN;
|
||||
}
|
||||
case 147: break;
|
||||
case 148: break;
|
||||
case 58:
|
||||
{ return RegExpTT.BAD_HEX_VALUE;
|
||||
}
|
||||
case 148: break;
|
||||
case 149: break;
|
||||
case 59:
|
||||
{ return allowTransformationEscapes ? RegExpTT.CHAR_CLASS : StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN;
|
||||
}
|
||||
case 149: break;
|
||||
case 150: break;
|
||||
case 60:
|
||||
{ return (allowHexDigitClass || allowHorizontalWhitespaceClass ? RegExpTT.CHAR_CLASS : StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN);
|
||||
}
|
||||
case 150: break;
|
||||
case 151: break;
|
||||
case 61:
|
||||
{ yypushstate(NAMED); return RegExpTT.NAMED_CHARACTER;
|
||||
}
|
||||
case 151: break;
|
||||
case 152: break;
|
||||
case 62:
|
||||
{ yypopstate(); return RegExpTT.QUOTE_END;
|
||||
}
|
||||
case 152: break;
|
||||
case 153: break;
|
||||
case 63:
|
||||
{ yybegin(CLASS2); return RegExpTT.REDUNDANT_ESCAPE;
|
||||
}
|
||||
case 153: break;
|
||||
case 154: break;
|
||||
case 64:
|
||||
// lookahead expression with fixed base length
|
||||
zzMarkedPos = Character.offsetByCodePoints
|
||||
@@ -1047,7 +1051,7 @@ class _RegExLexer implements FlexLexer {
|
||||
}
|
||||
return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 154: break;
|
||||
case 155: break;
|
||||
case 65:
|
||||
{ if (allowPosixBracketExpressions) {
|
||||
yybegin(BRACKET_EXPRESSION);
|
||||
@@ -1057,81 +1061,82 @@ class _RegExLexer implements FlexLexer {
|
||||
return RegExpTT.CHARACTER;
|
||||
}
|
||||
}
|
||||
case 155: break;
|
||||
case 156: break;
|
||||
case 66:
|
||||
{ if (allowNestedCharacterClasses) return RegExpTT.ANDAND; else yypushback(1); return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 156: break;
|
||||
case 157: break;
|
||||
case 67:
|
||||
{ yybegin(CLASS2); return RegExpTT.BRACKET_EXPRESSION_END;
|
||||
}
|
||||
case 157: break;
|
||||
case 158: break;
|
||||
case 68:
|
||||
{ yybegin(PY_COND_REF); return RegExpTT.PYTHON_COND_REF;
|
||||
}
|
||||
case 158: break;
|
||||
case 159: break;
|
||||
case 69:
|
||||
{ yybegin(NAMED_GROUP); capturingGroupCount++; return RegExpTT.RUBY_NAMED_GROUP;
|
||||
}
|
||||
case 159: break;
|
||||
case 160: break;
|
||||
case 70:
|
||||
{ yybegin(QUOTED_NAMED_GROUP); capturingGroupCount++; return RegExpTT.RUBY_QUOTED_NAMED_GROUP;
|
||||
}
|
||||
case 160: break;
|
||||
case 161: break;
|
||||
case 71:
|
||||
{ return RegExpTT.NON_CAPT_GROUP;
|
||||
}
|
||||
case 161: break;
|
||||
case 162: break;
|
||||
case 72:
|
||||
{ return RegExpTT.POS_LOOKAHEAD;
|
||||
}
|
||||
case 162: break;
|
||||
case 163: break;
|
||||
case 73:
|
||||
{ return RegExpTT.NEG_LOOKAHEAD;
|
||||
}
|
||||
case 163: break;
|
||||
case 164: break;
|
||||
case 74:
|
||||
// lookahead expression with fixed base length
|
||||
zzMarkedPos = Character.offsetByCodePoints
|
||||
(zzBufferL/*, zzStartRead, zzEndRead - zzStartRead*/, zzStartRead, 1);
|
||||
{ yypushstate(QUANTIFIER); return RegExpTT.LBRACE;
|
||||
}
|
||||
case 164: break;
|
||||
case 165: break;
|
||||
case 75:
|
||||
// lookahead expression with fixed base length
|
||||
zzMarkedPos = Character.offsetByCodePoints
|
||||
(zzBufferL/*, zzStartRead, zzEndRead - zzStartRead*/, zzStartRead, 1);
|
||||
{ if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(NEGATE_CLASS1); return RegExpTT.CLASS_BEGIN;
|
||||
{ if (yystate() == CLASS2 && !allowNestedCharacterClasses) return RegExpTT.CHARACTER;
|
||||
if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(NEGATE_CLASS1); return RegExpTT.CLASS_BEGIN;
|
||||
}
|
||||
case 165: break;
|
||||
case 166: break;
|
||||
case 76:
|
||||
{ return RegExpTT.OCT_CHAR;
|
||||
}
|
||||
case 166: break;
|
||||
case 167: break;
|
||||
case 77:
|
||||
{ yybegin(NAMED_GROUP); return RegExpTT.RUBY_NAMED_GROUP_CALL;
|
||||
}
|
||||
case 167: break;
|
||||
case 168: break;
|
||||
case 78:
|
||||
{ yybegin(QUOTED_NAMED_GROUP); return RegExpTT.RUBY_QUOTED_NAMED_GROUP_CALL;
|
||||
}
|
||||
case 168: break;
|
||||
case 169: break;
|
||||
case 79:
|
||||
{ if (xmlSchemaMode) { yypushback(1); return RegExpTT.CHAR_CLASS; } else return RegExpTT.CTRL;
|
||||
}
|
||||
case 169: break;
|
||||
case 170: break;
|
||||
case 80:
|
||||
{ return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN;
|
||||
}
|
||||
case 170: break;
|
||||
case 171: break;
|
||||
case 81:
|
||||
{ yybegin(NAMED_GROUP); return RegExpTT.RUBY_NAMED_GROUP_REF;
|
||||
}
|
||||
case 171: break;
|
||||
case 172: break;
|
||||
case 82:
|
||||
{ yybegin(QUOTED_NAMED_GROUP); return RegExpTT.RUBY_QUOTED_NAMED_GROUP_REF;
|
||||
}
|
||||
case 172: break;
|
||||
case 173: break;
|
||||
case 83:
|
||||
// lookahead expression with fixed base length
|
||||
zzMarkedPos = Character.offsetByCodePoints
|
||||
@@ -1142,35 +1147,43 @@ class _RegExLexer implements FlexLexer {
|
||||
}
|
||||
return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 173: break;
|
||||
case 174: break;
|
||||
case 84:
|
||||
{ yybegin(NAMED_GROUP); capturingGroupCount++; return RegExpTT.PYTHON_NAMED_GROUP;
|
||||
}
|
||||
case 174: break;
|
||||
case 175: break;
|
||||
case 85:
|
||||
{ yybegin(PY_NAMED_GROUP_REF); return RegExpTT.PYTHON_NAMED_GROUP_REF;
|
||||
}
|
||||
case 175: break;
|
||||
case 176: break;
|
||||
case 86:
|
||||
{ return RegExpTT.POS_LOOKBEHIND;
|
||||
}
|
||||
case 176: break;
|
||||
case 177: break;
|
||||
case 87:
|
||||
{ return RegExpTT.NEG_LOOKBEHIND;
|
||||
}
|
||||
case 177: break;
|
||||
case 88:
|
||||
{ return RegExpTT.HEX_CHAR;
|
||||
}
|
||||
case 178: break;
|
||||
case 89:
|
||||
{ return RegExpTT.COMMENT;
|
||||
case 88:
|
||||
// lookahead expression with fixed base length
|
||||
zzMarkedPos = Character.offsetByCodePoints
|
||||
(zzBufferL/*, zzStartRead, zzEndRead - zzStartRead*/, zzStartRead, 1);
|
||||
{ if (yystate() == CLASS2 && !allowNestedCharacterClasses) return RegExpTT.CHARACTER;
|
||||
if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(NEGATE_CLASS1); return RegExpTT.CLASS_BEGIN;
|
||||
}
|
||||
case 179: break;
|
||||
case 90:
|
||||
{ return RegExpTT.UNICODE_CHAR;
|
||||
case 89:
|
||||
{ return RegExpTT.HEX_CHAR;
|
||||
}
|
||||
case 180: break;
|
||||
case 90:
|
||||
{ return RegExpTT.COMMENT;
|
||||
}
|
||||
case 181: break;
|
||||
case 91:
|
||||
{ return RegExpTT.UNICODE_CHAR;
|
||||
}
|
||||
case 182: break;
|
||||
default:
|
||||
zzScanError(ZZ_NO_MATCH);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CustomShortcutSet;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.TransactionGuard;
|
||||
import com.intellij.openapi.application.TransactionId;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
@@ -112,19 +113,26 @@ public class CheckRegExpForm {
|
||||
}.registerCustomShortcutSet(CustomShortcutSet.fromString("shift TAB"), mySampleText);
|
||||
|
||||
final Alarm updater = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, disposable);
|
||||
Runnable scheduler = () -> {
|
||||
TransactionId transactionId = TransactionGuard.getInstance().getContextTransaction();
|
||||
updater.cancelAllRequests();
|
||||
if (!updater.isDisposed()) {
|
||||
updater.addRequest(() -> {
|
||||
Boolean correct = isMatchingText(myRegexpFile, mySampleText.getText());
|
||||
TransactionGuard.getInstance().submitTransaction(myProject, transactionId, () -> setBalloonState(correct));
|
||||
}, 200);
|
||||
}
|
||||
};
|
||||
DocumentAdapter documentListener = new DocumentAdapter() {
|
||||
@Override
|
||||
public void documentChanged(DocumentEvent e) {
|
||||
updater.cancelAllRequests();
|
||||
if (!updater.isDisposed()) {
|
||||
updater.addRequest(CheckRegExpForm.this::updateBalloon, 200);
|
||||
}
|
||||
scheduler.run();
|
||||
}
|
||||
};
|
||||
myRegExp.addDocumentListener(documentListener);
|
||||
mySampleText.addDocumentListener(documentListener);
|
||||
|
||||
updateBalloon();
|
||||
scheduler.run();
|
||||
mySampleText.selectAll();
|
||||
}
|
||||
|
||||
@@ -138,6 +146,14 @@ public class CheckRegExpForm {
|
||||
myRootPanel.setBorder(JBUI.Borders.empty(UIUtil.DEFAULT_VGAP, UIUtil.DEFAULT_HGAP));
|
||||
}
|
||||
|
||||
private void setBalloonState(Boolean correct) {
|
||||
mySampleText.setBackground(correct != null && correct ? BACKGROUND_COLOR_MATCH : BACKGROUND_COLOR_NOMATCH);
|
||||
myMessage.setText(correct == null ? "Pattern is too complex" : correct ? "Matches!" : "No match");
|
||||
myRootPanel.revalidate();
|
||||
Balloon balloon = JBPopupFactory.getInstance().getParentBalloonFor(myRootPanel);
|
||||
if (balloon != null && !balloon.isDisposed()) balloon.revalidate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return mySampleText;
|
||||
@@ -148,40 +164,24 @@ public class CheckRegExpForm {
|
||||
return myRootPanel;
|
||||
}
|
||||
|
||||
private void updateBalloon() {
|
||||
final Boolean correct = isMatchingText(myRegexpFile, mySampleText.getText());
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
mySampleText.setBackground(correct != null && correct ? BACKGROUND_COLOR_MATCH : BACKGROUND_COLOR_NOMATCH);
|
||||
myMessage.setText(correct == null ? "Pattern is too complex" : correct ? "Matches!" : "No match");
|
||||
myRootPanel.revalidate();
|
||||
Balloon balloon = JBPopupFactory.getInstance().getParentBalloonFor(myRootPanel);
|
||||
if (balloon != null && !balloon.isDisposed()) balloon.revalidate();
|
||||
});
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public static boolean isMatchingTextTest(@NotNull PsiFile regexpFile, @NotNull String sampleText) {
|
||||
Boolean result = isMatchingText(regexpFile, sampleText);
|
||||
return result != null && result;
|
||||
}
|
||||
|
||||
private static Boolean isMatchingText(@NotNull final PsiFile regexpFile, @NotNull String sampleText) {
|
||||
final String regExp = regexpFile.getText();
|
||||
|
||||
Integer patternFlags = ApplicationManager.getApplication().runReadAction(new Computable<Integer>() {
|
||||
@Override
|
||||
public Integer compute() {
|
||||
PsiLanguageInjectionHost host = InjectedLanguageUtil.findInjectionHost(regexpFile);
|
||||
int flags = 0;
|
||||
if (host != null) {
|
||||
for (RegExpModifierProvider provider : RegExpModifierProvider.EP.allForLanguage(host.getLanguage())) {
|
||||
flags = provider.getFlags(host, regexpFile);
|
||||
if (flags > 0) break;
|
||||
}
|
||||
Integer patternFlags = ApplicationManager.getApplication().runReadAction((Computable<Integer>)() -> {
|
||||
PsiLanguageInjectionHost host = InjectedLanguageUtil.findInjectionHost(regexpFile);
|
||||
int flags = 0;
|
||||
if (host != null) {
|
||||
for (RegExpModifierProvider provider : RegExpModifierProvider.EP.allForLanguage(host.getLanguage())) {
|
||||
flags = provider.getFlags(host, regexpFile);
|
||||
if (flags > 0) break;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
return flags;
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
@@ -259,14 +259,14 @@ HEX_CHAR=[0-9a-fA-F]
|
||||
}
|
||||
}
|
||||
|
||||
{LBRACKET} / {RBRACKET} { if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(CLASS1); return RegExpTT.CLASS_BEGIN; }
|
||||
{LBRACKET} / {ESCAPE} {RBRACKET} { if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(CLASS1); return RegExpTT.CLASS_BEGIN; }
|
||||
{LBRACKET} / ({RBRACKET} | {ESCAPE} {RBRACKET}) { if (yystate() == CLASS2 && !allowNestedCharacterClasses) return RegExpTT.CHARACTER;
|
||||
if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(CLASS1); return RegExpTT.CLASS_BEGIN; }
|
||||
|
||||
{LBRACKET} / "^" {RBRACKET} { if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(NEGATE_CLASS1); return RegExpTT.CLASS_BEGIN; }
|
||||
{LBRACKET} / "^" {ESCAPE} {RBRACKET} { if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(NEGATE_CLASS1); return RegExpTT.CLASS_BEGIN; }
|
||||
{LBRACKET} / "^" ({RBRACKET} | {ESCAPE} {RBRACKET}) { if (yystate() == CLASS2 && !allowNestedCharacterClasses) return RegExpTT.CHARACTER;
|
||||
if (allowEmptyCharacterClass) yypushstate(CLASS2); else yypushstate(NEGATE_CLASS1); return RegExpTT.CLASS_BEGIN; }
|
||||
|
||||
{LBRACKET} / "^" { yypushstate(NEGATE_CLASS2); return RegExpTT.CLASS_BEGIN; }
|
||||
{LBRACKET} { yypushstate(CLASS2); return RegExpTT.CLASS_BEGIN; }
|
||||
{LBRACKET} / "^" { if (yystate() == CLASS2 && !allowNestedCharacterClasses) return RegExpTT.CHARACTER; yypushstate(NEGATE_CLASS2); return RegExpTT.CLASS_BEGIN; }
|
||||
{LBRACKET} { if (yystate() == CLASS2 && !allowNestedCharacterClasses) return RegExpTT.CHARACTER; yypushstate(CLASS2); return RegExpTT.CLASS_BEGIN; }
|
||||
|
||||
/* []abc] is legal. The first ] is treated as literal character */
|
||||
<CLASS1> {
|
||||
@@ -387,3 +387,5 @@ HEX_CHAR=[0-9a-fA-F]
|
||||
[\n\b\t\r\f] { return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CTRL_CHARACTER; }
|
||||
|
||||
{ANY} { return RegExpTT.CHARACTER; }
|
||||
|
||||
}
|
||||
@@ -148,7 +148,7 @@ public class RegExpLexerTest extends LexerTestCase {
|
||||
"CLASS_END (']')", lexer);
|
||||
}
|
||||
|
||||
public void testNoNestedCharacterClasses() {
|
||||
public void testNoNestedCharacterClasses1() {
|
||||
final RegExpLexer lexer = new RegExpLexer(EnumSet.noneOf(RegExpCapability.class));
|
||||
doTest("[[\\]]", "CLASS_BEGIN ('[')\n" +
|
||||
"CHARACTER ('[')\n" +
|
||||
@@ -156,6 +156,50 @@ public class RegExpLexerTest extends LexerTestCase {
|
||||
"CLASS_END (']')", lexer);
|
||||
}
|
||||
|
||||
public void testNoNestedCharacterClasses2() {
|
||||
final RegExpLexer lexer = new RegExpLexer(EnumSet.noneOf(RegExpCapability.class));
|
||||
doTest("[a-z&&[^aeuoi]]", "CLASS_BEGIN ('[')\n" +
|
||||
"CHARACTER ('a')\n" +
|
||||
"MINUS ('-')\n" +
|
||||
"CHARACTER ('z')\n" +
|
||||
"CHARACTER ('&')\n" +
|
||||
"CHARACTER ('&')\n" +
|
||||
"CHARACTER ('[')\n" +
|
||||
"CHARACTER ('^')\n" +
|
||||
"CHARACTER ('a')\n" +
|
||||
"CHARACTER ('e')\n" +
|
||||
"CHARACTER ('u')\n" +
|
||||
"CHARACTER ('o')\n" +
|
||||
"CHARACTER ('i')\n" +
|
||||
"CLASS_END (']')\n" +
|
||||
"CHARACTER (']')", lexer);
|
||||
}
|
||||
|
||||
public void testNestedCharacterClasses1() {
|
||||
final RegExpLexer lexer = new RegExpLexer(EnumSet.of(RegExpCapability.NESTED_CHARACTER_CLASSES));
|
||||
doTest("[a-z&&[^aeuoi]]", "CLASS_BEGIN ('[')\n" +
|
||||
"CHARACTER ('a')\n" +
|
||||
"MINUS ('-')\n" +
|
||||
"CHARACTER ('z')\n" +
|
||||
"ANDAND ('&&')\n" +
|
||||
"CLASS_BEGIN ('[')\n" +
|
||||
"CARET ('^')\n" +
|
||||
"CHARACTER ('a')\n" +
|
||||
"CHARACTER ('e')\n" +
|
||||
"CHARACTER ('u')\n" +
|
||||
"CHARACTER ('o')\n" +
|
||||
"CHARACTER ('i')\n" +
|
||||
"CLASS_END (']')\n" +
|
||||
"CLASS_END (']')", lexer);
|
||||
}
|
||||
|
||||
public void testNestedCharacterClasses2() {
|
||||
final RegExpLexer lexer = new RegExpLexer(EnumSet.of(RegExpCapability.NESTED_CHARACTER_CLASSES));
|
||||
doTest("[]]", "CLASS_BEGIN ('[')\n" +
|
||||
"CHARACTER (']')\n" +
|
||||
"CLASS_END (']')", lexer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Lexer createLexer() {
|
||||
return null;
|
||||
|
||||
+25
-1
@@ -92,7 +92,7 @@ sun.java2d.pmoffscreen=false
|
||||
#---------------------------------------------------------------------
|
||||
# Enables HiDPI support in JBRE
|
||||
#---------------------------------------------------------------------
|
||||
sun.java2d.uiScale.enabled=true
|
||||
sun.java2d.uiScale.enabled=false
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Workaround to avoid long hangs while accessing clipboard under Mac OS X.
|
||||
@@ -111,3 +111,27 @@ sun.java2d.uiScale.enabled=true
|
||||
# Uncommenting the option prevents this behavior outside of user home directory.
|
||||
#---------------------------------------------------------------------
|
||||
#idea.chooser.lookup.for.project.dirs=false
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Experimental option that does a number of things to make truly smooth scrolling possible:
|
||||
#
|
||||
# * Enables hardware-accelerated scrolling.
|
||||
# Blit-acceleration copies as much of the rendered area as possible and then repaints only newly exposed region.
|
||||
# This helps to improve scrolling performance and to reduce CPU usage (especially if drawing is compute-intensive).
|
||||
#
|
||||
# * Enables "true double buffering".
|
||||
# True double buffering is needed to eliminate tearing on blit-accelerated scrolling and to restore
|
||||
# frame buffer content without the usual repainting, even when the EDT is blocked.
|
||||
#
|
||||
# * Adds "idea.true.smooth.scrolling.debug" option.
|
||||
# Checks whether blit-accelerated scrolling is feasible, and if so, checks whether true double buffering is available.
|
||||
#
|
||||
# * Enables handling of high-precision mouse wheel events.
|
||||
# Although Java 7 introduced MouseWheelEven.getPreciseWheelRotation() method, JScrollPane doesn't use it so far.
|
||||
# Depends on the Editor / General / Smooth Scrolling setting, remote desktop detection and power save mode state.
|
||||
#
|
||||
# * Enables interpolation of scrolling input (scrollbar thumb, mouse wheel, etc).
|
||||
# Smooths input which lacks both spatial and temporal resolution, performs the rendering asynchronously.
|
||||
# Depends on the Editor / General / Smooth Scrolling setting, remote desktop detection and power save mode state.
|
||||
#-----------------------------------------------------------------------
|
||||
#idea.true.smooth.scrolling=true
|
||||
|
||||
+17
-17
@@ -335,13 +335,13 @@ Function ConfirmDesktopShortcut
|
||||
!insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 3" "Text" $R1
|
||||
${EndIf}
|
||||
${If} ${RunningX64}
|
||||
; if 64-bit Win OS and jre64 for the build is available then add checkbox to Installation Options dialog
|
||||
StrCmp "${LINK_TO_JRE64}" "null" customPreActions 0
|
||||
inetc::head /SILENT /TOSTACK ${LINK_TO_JRE64} "" /END
|
||||
; if jre x86 for the build is available then add checkbox to Installation Options dialog
|
||||
StrCmp "${LINK_TO_JRE}" "null" customPreActions 0
|
||||
inetc::head /SILENT /TOSTACK ${LINK_TO_JRE} "" /END
|
||||
Pop $0
|
||||
${If} $0 == "OK"
|
||||
!insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 4" "Type" "checkbox"
|
||||
!insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 4" "Text" "Download and install 64-bit JRE by JetBrains (will be used with 64-bit launcher)"
|
||||
!insertmacro INSTALLOPTIONS_WRITE "Desktop.ini" "Field 4" "Text" "Download and install x86 JRE by JetBrains"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
@@ -366,21 +366,21 @@ done:
|
||||
!insertmacro INSTALLOPTIONS_DISPLAY "Desktop.ini"
|
||||
FunctionEnd
|
||||
|
||||
Function downloadJre64
|
||||
Function downloadJre
|
||||
!insertmacro INSTALLOPTIONS_READ $R0 "Desktop.ini" "Field 4" "State"
|
||||
${If} $R0 == 1
|
||||
inetc::get ${LINK_TO_JRE64} "$TEMP\jre64.tar.gz" /END
|
||||
inetc::get ${LINK_TO_JRE} "$TEMP\jre.tar.gz" /END
|
||||
Pop $0
|
||||
${If} $0 == "OK"
|
||||
untgz::extract "-d" "$INSTDIR\jre64" "$TEMP\jre64.tar.gz"
|
||||
StrCmp $R0 "success" removeTempJre64
|
||||
DetailPrint "Failed to extract jre64.tar.gz"
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION|MB_DEFBUTTON1 "Failed to extract $TEMP\jre64.tar.gz"
|
||||
removeTempJre64:
|
||||
IfFileExists "$TEMP\jre64.tar.gz" 0 done
|
||||
Delete "$TEMP\jre64.tar.gz"
|
||||
untgz::extract "-d" "$INSTDIR\jre" "$TEMP\jre.tar.gz"
|
||||
StrCmp $R0 "success" removeTempJre
|
||||
DetailPrint "Failed to extract jre.tar.gz"
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION|MB_DEFBUTTON1 "Failed to extract $TEMP\jre.tar.gz"
|
||||
removeTempJre:
|
||||
IfFileExists "$TEMP\jre.tar.gz" 0 done
|
||||
Delete "$TEMP\jre.tar.gz"
|
||||
${Else}
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION "The ${LINK_TO_JRE64} download is failed: $0"
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION "The ${LINK_TO_JRE} download is failed: $0"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
done:
|
||||
@@ -778,9 +778,9 @@ FunctionEnd
|
||||
;------------------------------------------------------------------------------
|
||||
Section "IDEA Files" CopyIdeaFiles
|
||||
|
||||
;download and install JRE 64
|
||||
StrCmp "${LINK_TO_JRE64}" "null" shortcuts 0
|
||||
Call downloadJre64
|
||||
StrCmp "${LINK_TO_JRE}" "null" shortcuts 0
|
||||
;download and install JRE x86
|
||||
Call downloadJre
|
||||
|
||||
shortcuts:
|
||||
;create shortcuts
|
||||
|
||||
@@ -80,7 +80,7 @@ class IdeaCommunityProperties extends BaseIdeaProperties {
|
||||
}
|
||||
|
||||
@Override
|
||||
String getBaseDownloadUrlForJre64() { "https://download.jetbrains.com/idea" }
|
||||
String getBaseDownloadUrlForJre() { "https://download.jetbrains.com/idea" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -321,6 +321,6 @@ class TeamCityBuildLocator {
|
||||
|
||||
String getDownloadUrl(String buildNumber) {
|
||||
String encodedBuildNumber = URLEncoder.encode(buildNumber, "UTF-8")
|
||||
return "$host/guestAuth/repository/download/$buildTypeId/$encodedBuildNumber/kotlin-plugin-1.0.5-release-IJ2016.3-2.zip"
|
||||
return "$host/guestAuth/repository/download/$buildTypeId/$encodedBuildNumber/kotlin-plugin-1.0.5-release-IJ2016.3-3.zip"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,5 +123,6 @@
|
||||
<orderEntry type="module" module-name="script-debugger-ui" scope="TEST" />
|
||||
<orderEntry type="module" module-name="remote-servers-git-java" />
|
||||
<orderEntry type="module" module-name="terminal" />
|
||||
<orderEntry type="module" module-name="javac-ref-scanner-8" scope="RUNTIME" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -5,7 +5,7 @@
|
||||
<company name="JetBrains s.r.o." url="https://www.jetbrains.com/?fromIDE"/>
|
||||
<build number="__BUILD_NUMBER__" date="__BUILD_DATE__"/>
|
||||
<logo url="/idea_community_logo.png" textcolor="dddddd" progressColor="f87206" progressX="117" progressY="280" progressHeight="3" />
|
||||
<about url="/idea_community_about.png" foreground="000000" copyrightForeground="7A858F" linkColor="9b5121" logoX="300" logoY="265" logoW="75" logoH="30"/>
|
||||
<about url="/idea_community_about.png" foreground="000000" copyrightForeground="7A858F" linkColor="9b5121" logoX="540" logoY="300" logoW="100" logoH="100"/>
|
||||
<icon size32="/icon_CE.png" size16="/icon_CEsmall.png" size128="/icon_CE_128.png" ico="idea_CE.ico"/>
|
||||
<package code="__PACKAGE_CODE__"/>
|
||||
<names product="IDEA" fullname="IntelliJ IDEA" script="idea"/>
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.intellij.openapi.compiler.CompilerBundle;
|
||||
import com.intellij.openapi.compiler.CompilerManager;
|
||||
import com.intellij.openapi.compiler.options.ExcludeEntryDescription;
|
||||
import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration;
|
||||
import com.intellij.openapi.compiler.options.ExcludedEntriesListener;
|
||||
import com.intellij.openapi.compiler.options.ExcludesConfiguration;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.ProjectComponent;
|
||||
@@ -38,7 +39,7 @@ import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.ModuleAdapter;
|
||||
import com.intellij.openapi.project.ModuleListener;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.ui.InputValidator;
|
||||
@@ -88,7 +89,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
|
||||
private final List<CompiledPattern> myNegatedCompiledPatterns = new ArrayList<>();
|
||||
private boolean myWildcardPatternsInitialized = false;
|
||||
private final Project myProject;
|
||||
private final ExcludesConfigNotificationsWrapper<ExcludedEntriesConfiguration> myExcludesConfiguration;
|
||||
private final ExcludedEntriesConfiguration myExcludesConfiguration;
|
||||
|
||||
private final Collection<BackendCompiler> myRegisteredCompilers = new ArrayList<>();
|
||||
private JavacCompiler JAVAC_EXTERNAL_BACKEND;
|
||||
@@ -111,10 +112,21 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
|
||||
|
||||
public CompilerConfigurationImpl(Project project) {
|
||||
myProject = project;
|
||||
myExcludesConfiguration = new ExcludesConfigNotificationsWrapper<>(project, new ExcludedEntriesConfiguration());
|
||||
Disposer.register(project, myExcludesConfiguration.getDelegate());
|
||||
myExcludesConfiguration = new ExcludedEntriesConfiguration(project.getMessageBus().syncPublisher(ExcludedEntriesListener.TOPIC));
|
||||
Disposer.register(project, myExcludesConfiguration);
|
||||
project.getMessageBus().connect().subscribe(ExcludedEntriesListener.TOPIC, new ExcludedEntriesListener() {
|
||||
@Override
|
||||
public void onEntryAdded(@NotNull ExcludeEntryDescription description) {
|
||||
BuildManager.getInstance().clearState(myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryRemoved(@NotNull ExcludeEntryDescription description) {
|
||||
BuildManager.getInstance().clearState(myProject);
|
||||
}
|
||||
});
|
||||
MessageBusConnection connection = project.getMessageBus().connect(project);
|
||||
connection.subscribe(ProjectTopics.MODULES, new ModuleAdapter() {
|
||||
connection.subscribe(ProjectTopics.MODULES, new ModuleListener() {
|
||||
@Override
|
||||
public void beforeModuleRemoved(@NotNull Project project, @NotNull Module module) {
|
||||
getAnnotationProcessingConfiguration(module).removeModuleName(module.getName());
|
||||
@@ -150,7 +162,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
|
||||
}
|
||||
|
||||
if (myExcludesConfiguration.getExcludeEntryDescriptions().length > 0) {
|
||||
myExcludesConfiguration.getDelegate().writeExternal(addChild(state, JpsJavaCompilerConfigurationSerializer.EXCLUDE_FROM_COMPILE));
|
||||
myExcludesConfiguration.writeExternal(addChild(state, JpsJavaCompilerConfigurationSerializer.EXCLUDE_FROM_COMPILE));
|
||||
}
|
||||
|
||||
Element resourceExtensions = new Element(JpsJavaCompilerConfigurationSerializer.RESOURCE_EXTENSIONS);
|
||||
@@ -703,7 +715,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
|
||||
|
||||
Element node = parentNode.getChild(JpsJavaCompilerConfigurationSerializer.EXCLUDE_FROM_COMPILE);
|
||||
if (node != null) {
|
||||
myExcludesConfiguration.getDelegate().readExternal(node);
|
||||
myExcludesConfiguration.readExternal(node);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -1024,65 +1036,4 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
|
||||
parent.addContent(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
private static class ExcludesConfigNotificationsWrapper<T extends ExcludesConfiguration> implements ExcludesConfiguration {
|
||||
private final Project myProject;
|
||||
private final T myDelegate;
|
||||
|
||||
public ExcludesConfigNotificationsWrapper(@NotNull Project project, @NotNull T delegate) {
|
||||
myProject = project;
|
||||
myDelegate = delegate;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public T getDelegate() {
|
||||
return myDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExcludeEntryDescription[] getExcludeEntryDescriptions() {
|
||||
return myDelegate.getExcludeEntryDescriptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addExcludeEntryDescription(ExcludeEntryDescription description) {
|
||||
try {
|
||||
myDelegate.addExcludeEntryDescription(description);
|
||||
}
|
||||
finally {
|
||||
BuildManager.getInstance().clearState(myProject);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeExcludeEntryDescription(ExcludeEntryDescription description) {
|
||||
try {
|
||||
myDelegate.removeExcludeEntryDescription(description);
|
||||
}
|
||||
finally {
|
||||
BuildManager.getInstance().clearState(myProject);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllExcludeEntryDescriptions() {
|
||||
try {
|
||||
myDelegate.removeAllExcludeEntryDescriptions();
|
||||
}
|
||||
finally {
|
||||
BuildManager.getInstance().clearState(myProject);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsExcludeEntryDescription(ExcludeEntryDescription description) {
|
||||
return myDelegate.containsExcludeEntryDescription(description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExcluded(VirtualFile virtualFile) {
|
||||
return myDelegate.isExcluded(virtualFile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import com.intellij.openapi.compiler.*;
|
||||
import com.intellij.openapi.compiler.Compiler;
|
||||
import com.intellij.openapi.compiler.util.InspectionValidator;
|
||||
import com.intellij.openapi.compiler.util.InspectionValidatorWrapper;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
@@ -64,6 +65,8 @@ import java.util.*;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public class CompilerManagerImpl extends CompilerManager {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.CompilerManagerImpl");
|
||||
|
||||
private final Project myProject;
|
||||
|
||||
private final List<Compiler> myCompilers = new ArrayList<>();
|
||||
@@ -507,6 +510,9 @@ public class CompilerManagerImpl extends CompilerManager {
|
||||
public void outputLineAvailable(String line) {
|
||||
// for debugging purposes uncomment this line
|
||||
//System.out.println(line);
|
||||
if (line != null && line.startsWith(ExternalJavacManager.STDERR_LINE_PREFIX)) {
|
||||
LOG.info(line.trim());
|
||||
}
|
||||
}
|
||||
|
||||
public void registerImports(String className, Collection<String> imports, Collection<String> staticImports) {
|
||||
|
||||
+5
-5
@@ -18,7 +18,7 @@ package com.intellij.compiler.backwardRefs;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.psi.impl.source.PsiFileWithStubSupport;
|
||||
import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator;
|
||||
import org.jetbrains.jps.backwardRefs.NameEnumerator;
|
||||
import org.jetbrains.jps.backwardRefs.LightRef;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -39,8 +39,8 @@ enum CompilerHierarchySearchType {
|
||||
}
|
||||
|
||||
@Override
|
||||
Object[] convertToIds(Collection<LightRef> lightRef, ByteArrayEnumerator byteArrayEnumerator) {
|
||||
return lightRef.stream().map(r -> byteArrayEnumerator.getName(((LightRef.LightClassHierarchyElementDef)r).getName())).toArray(String[]::new);
|
||||
Object[] convertToIds(Collection<LightRef> lightRef, NameEnumerator nameEnumerator) {
|
||||
return lightRef.stream().map(r -> nameEnumerator.getName(((LightRef.LightClassHierarchyElementDef)r).getName())).toArray(String[]::new);
|
||||
}
|
||||
},
|
||||
FUNCTIONAL_EXPRESSION {
|
||||
@@ -58,7 +58,7 @@ enum CompilerHierarchySearchType {
|
||||
}
|
||||
|
||||
@Override
|
||||
Object[] convertToIds(Collection<LightRef> lightRef, ByteArrayEnumerator byteArrayEnumerator) {
|
||||
Object[] convertToIds(Collection<LightRef> lightRef, NameEnumerator nameEnumerator) {
|
||||
return lightRef.stream().map(r -> ((LightRef.LightFunExprDef) r).getId()).toArray(Integer[]::new);
|
||||
}
|
||||
};
|
||||
@@ -70,5 +70,5 @@ enum CompilerHierarchySearchType {
|
||||
|
||||
abstract Class<? extends LightRef> getRequiredClass(LanguageLightRefAdapter adapter);
|
||||
|
||||
abstract Object[] convertToIds(Collection<LightRef> lightRef, ByteArrayEnumerator byteArrayEnumerator);
|
||||
abstract Object[] convertToIds(Collection<LightRef> lightRef, NameEnumerator nameEnumerator);
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ import gnu.trove.THashSet;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator;
|
||||
import org.jetbrains.jps.backwardRefs.NameEnumerator;
|
||||
import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex;
|
||||
import org.jetbrains.jps.backwardRefs.LightRef;
|
||||
import org.jetbrains.jps.backwardRefs.index.CompilerIndices;
|
||||
@@ -96,7 +96,7 @@ class CompilerReferenceReader {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
ByteArrayEnumerator getNameEnumerator() {
|
||||
NameEnumerator getNameEnumerator() {
|
||||
return myIndex.getByteSeqEum();
|
||||
}
|
||||
|
||||
|
||||
+32
-29
@@ -68,7 +68,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
private final static Logger LOG = Logger.getInstance(CompilerReferenceServiceImpl.class);
|
||||
|
||||
private final Set<FileType> myFileTypes;
|
||||
private final DirtyModulesHolder myDirtyModulesHolder;
|
||||
private final DirtyScopeHolder myDirtyScopeHolder;
|
||||
private final ProjectFileIndex myProjectFileIndex;
|
||||
private final LongAdder myCompilationCount = new LongAdder();
|
||||
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
|
||||
@@ -82,7 +82,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
|
||||
myProjectFileIndex = ProjectRootManager.getInstance(project).getFileIndex();
|
||||
myFileTypes = Stream.of(LanguageLightRefAdapter.INSTANCES).flatMap(a -> a.getFileTypes().stream()).collect(Collectors.toSet());
|
||||
myDirtyModulesHolder = new DirtyModulesHolder(this, fileDocumentManager, psiDocumentManager);
|
||||
myDirtyScopeHolder = new DirtyScopeHolder(this, fileDocumentManager, psiDocumentManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,7 +91,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
myProject.getMessageBus().connect(myProject).subscribe(BuildManagerListener.TOPIC, new BuildManagerListener() {
|
||||
@Override
|
||||
public void buildStarted(Project project, UUID sessionId, boolean isAutomake) {
|
||||
myDirtyModulesHolder.compilerActivityStarted();
|
||||
myDirtyScopeHolder.compilerActivityStarted();
|
||||
closeReaderIfNeed();
|
||||
}
|
||||
});
|
||||
@@ -127,9 +127,9 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
modulesWithErrors = Collections.emptySet();
|
||||
}
|
||||
if (modulesWithErrors.contains(null) /*unknown error location*/) {
|
||||
myDirtyModulesHolder.compilerActivityFinished(Module.EMPTY_ARRAY, compilationModules);
|
||||
myDirtyScopeHolder.compilerActivityFinished(Module.EMPTY_ARRAY, compilationModules);
|
||||
} else {
|
||||
myDirtyModulesHolder.compilerActivityFinished(compilationModules, modulesWithErrors.toArray(Module.EMPTY_ARRAY));
|
||||
myDirtyScopeHolder.compilerActivityFinished(compilationModules, modulesWithErrors.toArray(Module.EMPTY_ARRAY));
|
||||
}
|
||||
|
||||
myCompilationCount.increment();
|
||||
@@ -139,27 +139,29 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
}
|
||||
});
|
||||
|
||||
myDirtyModulesHolder.installVFSListener();
|
||||
myDirtyScopeHolder.installVFSListener();
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
CompileScope projectCompileScope = compilerManager.createProjectCompileScope(myProject);
|
||||
boolean isUpToDate = compilerManager.isUpToDate(projectCompileScope);
|
||||
executeOnBuildThread(() -> {
|
||||
Module[] modules = ReadAction.compute(() -> {
|
||||
if (myProject.isDisposed()) return null;
|
||||
return projectCompileScope.getAffectedModules();
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
CompileScope projectCompileScope = compilerManager.createProjectCompileScope(myProject);
|
||||
boolean isUpToDate = compilerManager.isUpToDate(projectCompileScope);
|
||||
executeOnBuildThread(() -> {
|
||||
Module[] modules = ReadAction.compute(() -> {
|
||||
if (myProject.isDisposed()) return null;
|
||||
return projectCompileScope.getAffectedModules();
|
||||
});
|
||||
if (modules == null) return;
|
||||
if (isUpToDate) {
|
||||
myDirtyScopeHolder.compilerActivityFinished(modules, Module.EMPTY_ARRAY);
|
||||
myCompilationCount.increment();
|
||||
openReaderIfNeed();
|
||||
}
|
||||
else {
|
||||
myDirtyScopeHolder.compilerActivityFinished(Module.EMPTY_ARRAY, modules);
|
||||
}
|
||||
});
|
||||
if (modules == null) return;
|
||||
if (isUpToDate) {
|
||||
myDirtyModulesHolder.compilerActivityFinished(modules, Module.EMPTY_ARRAY);
|
||||
myCompilationCount.increment();
|
||||
openReaderIfNeed();
|
||||
}
|
||||
else {
|
||||
myDirtyModulesHolder.compilerActivityFinished(Module.EMPTY_ARRAY, modules);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +233,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
});
|
||||
|
||||
if (candidatesPerFile == null) return null;
|
||||
GlobalSearchScope dirtyScope = myDirtyModulesHolder.getDirtyScope();
|
||||
GlobalSearchScope dirtyScope = myDirtyScopeHolder.getDirtyScope();
|
||||
if (ElementPlace.LIB == ReadAction.compute(() -> ElementPlace.get(aClass.getContainingFile().getVirtualFile(), myProjectFileIndex))) {
|
||||
dirtyScope = dirtyScope.union(LibraryScopeCache.getInstance(myProject).getLibrariesOnlyScope());
|
||||
}
|
||||
@@ -268,7 +270,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
try {
|
||||
if (myReader == null) return null;
|
||||
try {
|
||||
return myReader.getDirectInheritors(searchElement, useScope, myDirtyModulesHolder.getDirtyScope(), searchFileType, searchType);
|
||||
return myReader.getDirectInheritors(searchElement, useScope, myDirtyScopeHolder.getDirtyScope(), searchFileType, searchType);
|
||||
}
|
||||
catch (StorageException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -283,7 +285,8 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
TIntHashSet referentFileIds = getReferentFileIds(element);
|
||||
if (referentFileIds == null) return null;
|
||||
|
||||
return getScopeRestrictedByFileTypes(new ScopeWithoutReferencesOnCompilation(referentFileIds, myProjectFileIndex).intersectWith(notScope(myDirtyModulesHolder.getDirtyScope())),
|
||||
return getScopeRestrictedByFileTypes(new ScopeWithoutReferencesOnCompilation(referentFileIds, myProjectFileIndex).intersectWith(notScope(
|
||||
myDirtyScopeHolder.getDirtyScope())),
|
||||
myFileTypes.toArray(new FileType[myFileTypes.size()]));
|
||||
}
|
||||
|
||||
@@ -321,7 +324,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
VirtualFile file = PsiUtilCore.getVirtualFile(psiElement);
|
||||
if (file == null) return null;
|
||||
ElementPlace place = ElementPlace.get(file, myProjectFileIndex);
|
||||
if (place == null || (place == ElementPlace.SRC && myDirtyModulesHolder.contains(file))) {
|
||||
if (place == null || (place == ElementPlace.SRC && myDirtyScopeHolder.contains(file))) {
|
||||
return null;
|
||||
}
|
||||
final LanguageLightRefAdapter adapter = findAdapterForFileType(file.getFileType());
|
||||
@@ -498,7 +501,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
|
||||
@TestOnly
|
||||
@NotNull
|
||||
public DirtyModulesHolder getDirtyModulesHolder() {
|
||||
return myDirtyModulesHolder;
|
||||
public DirtyScopeHolder getDirtyScopeHolder() {
|
||||
return myDirtyScopeHolder;
|
||||
}
|
||||
}
|
||||
|
||||
+39
-10
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
package com.intellij.compiler.backwardRefs;
|
||||
|
||||
import com.intellij.compiler.CompilerConfiguration;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.compiler.options.ExcludeEntryDescription;
|
||||
import com.intellij.openapi.compiler.options.ExcludedEntriesListener;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
@@ -29,39 +32,57 @@ import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class DirtyModulesHolder extends UserDataHolderBase {
|
||||
public class DirtyScopeHolder extends UserDataHolderBase {
|
||||
private final CompilerReferenceServiceImpl myService;
|
||||
private final FileDocumentManager myFileDocManager;
|
||||
private final PsiDocumentManager myPsiDocManager;
|
||||
private final Set<Module> myVFSChangedModules = ContainerUtil.newHashSet();
|
||||
private final Set<Module> myChangedModulesDuringCompilation = ContainerUtil.newHashSet();
|
||||
private final Object myLock = new Object();
|
||||
|
||||
private boolean myCompilationPhase;
|
||||
private final Set<Module> myVFSChangedModules = ContainerUtil.newHashSet(); // guarded by myLock
|
||||
private final Set<Module> myChangedModulesDuringCompilation = ContainerUtil.newHashSet(); // guarded by myLock
|
||||
private final List<ExcludeEntryDescription> myExcludedDescriptions = new SmartList<>(); // guarded by myLock
|
||||
private boolean myCompilationPhase; // guarded by myLock
|
||||
private volatile GlobalSearchScope myExcludedFilesScope; // calculated outside myLock
|
||||
|
||||
public DirtyModulesHolder(@NotNull CompilerReferenceServiceImpl service,
|
||||
FileDocumentManager fileDocumentManager,
|
||||
PsiDocumentManager psiDocumentManager){
|
||||
public DirtyScopeHolder(@NotNull CompilerReferenceServiceImpl service,
|
||||
FileDocumentManager fileDocumentManager,
|
||||
PsiDocumentManager psiDocumentManager){
|
||||
myService = service;
|
||||
myFileDocManager = fileDocumentManager;
|
||||
myPsiDocManager = psiDocumentManager;
|
||||
|
||||
service.getProject().getMessageBus().connect().subscribe(ExcludedEntriesListener.TOPIC, new ExcludedEntriesListener() {
|
||||
@Override
|
||||
public void onEntryAdded(@NotNull ExcludeEntryDescription description) {
|
||||
synchronized (myLock) {
|
||||
if (myCompilationPhase) {
|
||||
myExcludedDescriptions.add(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void compilerActivityStarted() {
|
||||
synchronized (myLock) {
|
||||
myCompilationPhase = true;
|
||||
Collections.addAll(myExcludedDescriptions, CompilerConfiguration.getInstance(myService.getProject()).getExcludedEntriesConfiguration().getExcludeEntryDescriptions());
|
||||
myExcludedFilesScope = null;
|
||||
}
|
||||
}
|
||||
|
||||
void compilerActivityFinished(Module[] affectedModules, Module[] markAsDirty) {
|
||||
ExcludeEntryDescription[] descriptions;
|
||||
synchronized (myLock) {
|
||||
myCompilationPhase = false;
|
||||
|
||||
@@ -69,7 +90,10 @@ public class DirtyModulesHolder extends UserDataHolderBase {
|
||||
Collections.addAll(myVFSChangedModules, markAsDirty);
|
||||
myVFSChangedModules.addAll(myChangedModulesDuringCompilation);
|
||||
myChangedModulesDuringCompilation.clear();
|
||||
descriptions = myExcludedDescriptions.toArray(new ExcludeEntryDescription[myExcludedDescriptions.size()]);
|
||||
myExcludedDescriptions.clear();
|
||||
}
|
||||
myExcludedFilesScope = ExcludedFromCompileFilesUtil.getExcludedFilesScope(descriptions, myService.getFileTypes(), myService.getProject(), myService.getFileIndex());
|
||||
}
|
||||
|
||||
GlobalSearchScope getDirtyScope() {
|
||||
@@ -81,13 +105,18 @@ public class DirtyModulesHolder extends UserDataHolderBase {
|
||||
return ReadAction.compute(() -> {
|
||||
if (project.isDisposed()) throw new ProcessCanceledException();
|
||||
return CachedValuesManager.getManager(project).getCachedValue(this, () ->
|
||||
CachedValueProvider.Result.create(calculateDirtyModules(), PsiModificationTracker.MODIFICATION_COUNT, VirtualFileManager.getInstance(), myService));
|
||||
CachedValueProvider.Result.create(calculateDirtyScope(), PsiModificationTracker.MODIFICATION_COUNT, VirtualFileManager.getInstance(), myService));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private GlobalSearchScope calculateDirtyModules() {
|
||||
return getAllDirtyModules().stream().map(Module::getModuleWithDependentsScope).reduce(GlobalSearchScope.EMPTY_SCOPE, (s1, s2) -> s1.union(s2));
|
||||
private GlobalSearchScope calculateDirtyScope() {
|
||||
final GlobalSearchScope dirtyModuleScope = getAllDirtyModules()
|
||||
.stream()
|
||||
.map(Module::getModuleWithDependentsScope)
|
||||
.reduce(GlobalSearchScope.EMPTY_SCOPE, (s1, s2) -> s1.union(s2));
|
||||
|
||||
return dirtyModuleScope.union(myExcludedFilesScope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 com.intellij.compiler.backwardRefs;
|
||||
|
||||
import com.intellij.openapi.compiler.options.ExcludeEntryDescription;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.ManagingFS;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class ExcludedFromCompileFilesUtil {
|
||||
static GlobalSearchScope getExcludedFilesScope(@NotNull ExcludeEntryDescription[] descriptions,
|
||||
@NotNull Set<FileType> fileTypes,
|
||||
@NotNull Project project,
|
||||
@NotNull ProjectFileIndex fileIndex) {
|
||||
ManagingFS fs = ManagingFS.getInstance();
|
||||
final Collection<VirtualFile> excludedFiles = Stream.of(descriptions)
|
||||
.flatMap(description -> {
|
||||
final VirtualFile file = description.getVirtualFile();
|
||||
if (file == null) return Stream.empty();
|
||||
if (description.isFile()) {
|
||||
return Stream.of(file);
|
||||
}
|
||||
else if (description.isIncludeSubdirectories()) {
|
||||
final Stream.Builder<VirtualFile> builder = Stream.builder();
|
||||
VfsUtilCore.iterateChildrenRecursively(file, f -> !f.isDirectory() || fs.areChildrenLoaded(f), f -> {
|
||||
builder.accept(f);
|
||||
return true;
|
||||
});
|
||||
return builder.build();
|
||||
}
|
||||
else {
|
||||
return fs.areChildrenLoaded(file) ? Stream.of(file.getChildren()) : Stream.empty();
|
||||
}
|
||||
})
|
||||
.filter(f -> !f.isDirectory() && fileTypes.contains(f.getFileType()) && fileIndex.isInSourceContent(f))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return GlobalSearchScope.filesWithoutLibrariesScope(project, excludedFiles);
|
||||
}
|
||||
}
|
||||
+7
-12
@@ -28,10 +28,9 @@ import com.intellij.psi.util.ClassUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator;
|
||||
import org.jetbrains.jps.backwardRefs.NameEnumerator;
|
||||
import org.jetbrains.jps.backwardRefs.LightRef;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -46,7 +45,7 @@ public class JavaLightUsageAdapter implements LanguageLightRefAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public LightRef asLightUsage(@NotNull PsiElement element, @NotNull ByteArrayEnumerator names) {
|
||||
public LightRef asLightUsage(@NotNull PsiElement element, @NotNull NameEnumerator names) {
|
||||
if (mayBeVisibleOutsideOwnerFile(element)) {
|
||||
if (element instanceof PsiField) {
|
||||
final PsiField field = (PsiField)element;
|
||||
@@ -55,7 +54,7 @@ public class JavaLightUsageAdapter implements LanguageLightRefAdapter {
|
||||
final String jvmOwnerName = ClassUtil.getJVMClassName(aClass);
|
||||
final String name = field.getName();
|
||||
if (name == null || jvmOwnerName == null) return null;
|
||||
return new LightRef.JavaLightFieldRef(id(jvmOwnerName, names), id(name, names));
|
||||
return new LightRef.JavaLightFieldRef(names.enumerate(jvmOwnerName), names.enumerate(name));
|
||||
}
|
||||
else if (element instanceof PsiMethod) {
|
||||
final PsiClass aClass = ((PsiMethod)element).getContainingClass();
|
||||
@@ -65,12 +64,12 @@ public class JavaLightUsageAdapter implements LanguageLightRefAdapter {
|
||||
final PsiMethod method = (PsiMethod)element;
|
||||
final String name = method.isConstructor() ? "<init>" : method.getName();
|
||||
final int parametersCount = method.getParameterList().getParametersCount();
|
||||
return new LightRef.JavaLightMethodRef(id(jvmOwnerName, names), id(name, names), parametersCount);
|
||||
return new LightRef.JavaLightMethodRef(names.enumerate(jvmOwnerName), names.enumerate(name), parametersCount);
|
||||
}
|
||||
else if (element instanceof PsiClass) {
|
||||
final String jvmClassName = ClassUtil.getJVMClassName((PsiClass)element);
|
||||
if (jvmClassName != null) {
|
||||
return new LightRef.JavaLightClassRef(id(jvmClassName, names));
|
||||
return new LightRef.JavaLightClassRef(names.enumerate(jvmClassName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +80,7 @@ public class JavaLightUsageAdapter implements LanguageLightRefAdapter {
|
||||
@Override
|
||||
public List<LightRef> getHierarchyRestrictedToLibraryScope(@NotNull LightRef baseRef,
|
||||
@NotNull PsiElement basePsi,
|
||||
@NotNull ByteArrayEnumerator names, @NotNull GlobalSearchScope libraryScope) {
|
||||
@NotNull NameEnumerator names, @NotNull GlobalSearchScope libraryScope) {
|
||||
final PsiClass baseClass = ObjectUtils.notNull(basePsi instanceof PsiClass ? (PsiClass)basePsi : ReadAction.compute(() -> (PsiMember)basePsi).getContainingClass());
|
||||
|
||||
final List<LightRef> overridden = new ArrayList<>();
|
||||
@@ -89,7 +88,7 @@ public class JavaLightUsageAdapter implements LanguageLightRefAdapter {
|
||||
if (c.hasModifierProperty(PsiModifier.PRIVATE)) return true;
|
||||
String qName = ReadAction.compute(() -> c.getQualifiedName());
|
||||
if (qName == null) return true;
|
||||
overridden.add(baseRef.override(id(qName, names)));
|
||||
overridden.add(baseRef.override(names.enumerate(qName)));
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -139,8 +138,4 @@ public class JavaLightUsageAdapter implements LanguageLightRefAdapter {
|
||||
if (((PsiModifierListOwner)element).hasModifierProperty(PsiModifier.PRIVATE)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int id(String name, ByteArrayEnumerator names) {
|
||||
return names.enumerate(Convert.string2utf(name));
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -22,7 +22,7 @@ import com.intellij.psi.impl.source.PsiFileWithStubSupport;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator;
|
||||
import org.jetbrains.jps.backwardRefs.NameEnumerator;
|
||||
import org.jetbrains.jps.backwardRefs.LightRef;
|
||||
|
||||
import java.util.List;
|
||||
@@ -43,7 +43,7 @@ public interface LanguageLightRefAdapter {
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
LightRef asLightUsage(@NotNull PsiElement element, @NotNull ByteArrayEnumerator names);
|
||||
LightRef asLightUsage(@NotNull PsiElement element, @NotNull NameEnumerator names);
|
||||
|
||||
/**
|
||||
* @return "hierarchy" of given element inside the libraries scope.
|
||||
@@ -51,7 +51,7 @@ public interface LanguageLightRefAdapter {
|
||||
@NotNull
|
||||
List<LightRef> getHierarchyRestrictedToLibraryScope(@NotNull LightRef baseRef,
|
||||
@NotNull PsiElement basePsi,
|
||||
@NotNull ByteArrayEnumerator names,
|
||||
@NotNull NameEnumerator names,
|
||||
@NotNull GlobalSearchScope libraryScope);
|
||||
|
||||
/**
|
||||
|
||||
+9
-3
@@ -17,6 +17,7 @@ package com.intellij.compiler.options;
|
||||
|
||||
import com.intellij.compiler.CompilerConfiguration;
|
||||
import com.intellij.compiler.CompilerConfigurationImpl;
|
||||
import com.intellij.compiler.server.BuildManager;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SearchableConfigurable;
|
||||
@@ -85,9 +86,14 @@ public class AnnotationProcessorsConfigurable implements SearchableConfigurable,
|
||||
}
|
||||
|
||||
public void apply() throws ConfigurationException {
|
||||
final CompilerConfigurationImpl config = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject);
|
||||
config.setDefaultProcessorProfile(myMainPanel.getDefaultProfile());
|
||||
config.setModuleProcessorProfiles(myMainPanel.getModuleProfiles());
|
||||
try {
|
||||
final CompilerConfigurationImpl config = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject);
|
||||
config.setDefaultProcessorProfile(myMainPanel.getDefaultProfile());
|
||||
config.setModuleProcessorProfiles(myMainPanel.getModuleProfiles());
|
||||
}
|
||||
finally {
|
||||
BuildManager.getInstance().clearState(myProject);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.compiler.options.CompilerUIConfigurable">
|
||||
<grid id="1663f" binding="myPanel" layout-manager="GridLayoutManager" row-count="12" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="1663f" binding="myPanel" layout-manager="GridLayoutManager" row-count="13" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="28" y="24" width="883" height="379"/>
|
||||
@@ -8,11 +8,6 @@
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<vspacer id="67edf">
|
||||
<constraints>
|
||||
<grid row="11" column="0" row-span="1" col-span="3" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<grid id="b341d" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
@@ -195,6 +190,19 @@
|
||||
</hspacer>
|
||||
</children>
|
||||
</grid>
|
||||
<component id="5c3dc" class="javax.swing.JLabel" binding="myWarningLabel">
|
||||
<constraints>
|
||||
<grid row="12" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Label"/>
|
||||
</properties>
|
||||
</component>
|
||||
<vspacer id="60b1c">
|
||||
<constraints>
|
||||
<grid row="11" column="2" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
|
||||
@@ -86,6 +86,7 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
|
||||
private JLabel myEnableAutomakeLegendLabel;
|
||||
private JLabel myParallelCompilationLegendLabel;
|
||||
private JButton myConfigureAnnotations;
|
||||
private JLabel myWarningLabel;
|
||||
|
||||
public CompilerUIConfigurable(@NotNull final Project project) {
|
||||
myProject = project;
|
||||
@@ -96,6 +97,12 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
|
||||
"<b>/</b> — path separator; <b>/**/</b> — any number of directories; " +
|
||||
"<i><dir_name></i>:<i><pattern></i> — restrict to source roots with the specified name"
|
||||
));
|
||||
myWarningLabel.setText("<html>WARNING!<br>" +
|
||||
/*"All source files located in the generated sources output directory WILL BE EXCLUDED from annotation processing. " +*/
|
||||
"If option 'Clear output directory on rebuild' is enabled, " +
|
||||
"the entire contents of directories where generated sources are stored WILL BE CLEARED on rebuild.</html>");
|
||||
myWarningLabel.setFont(myWarningLabel.getFont().deriveFont(Font.BOLD));
|
||||
|
||||
myPatternLegendLabel.setForeground(new JBColor(Gray._50, Gray._130));
|
||||
tweakControls(project);
|
||||
myVMOptionsField.getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
@@ -109,7 +116,9 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(myPanel));
|
||||
if (project == null) project = ProjectManager.getInstance().getDefaultProject();
|
||||
if (project == null) {
|
||||
project = ProjectManager.getInstance().getDefaultProject();
|
||||
}
|
||||
new NullableNotNullDialog(project).show();
|
||||
}
|
||||
});
|
||||
@@ -142,18 +151,16 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
|
||||
}
|
||||
|
||||
Map<Setting, Collection<JComponent>> controls = ContainerUtilRt.newHashMap();
|
||||
controls.put(Setting.RESOURCE_PATTERNS,
|
||||
ContainerUtilRt.<JComponent>newArrayList(myResourcePatternsLabel, myResourcePatternsField, myPatternLegendLabel));
|
||||
controls.put(Setting.CLEAR_OUTPUT_DIR_ON_REBUILD, Collections.<JComponent>singleton(myCbClearOutputDirectory));
|
||||
controls.put(Setting.ADD_NOT_NULL_ASSERTIONS, Collections.<JComponent>singleton(myCbAssertNotNull));
|
||||
controls.put(Setting.AUTO_SHOW_FIRST_ERROR_IN_EDITOR, Collections.<JComponent>singleton(myCbAutoShowFirstError));
|
||||
controls.put(Setting.DISPLAY_NOTIFICATION_POPUP, Collections.<JComponent>singleton(myCbDisplayNotificationPopup));
|
||||
controls.put(Setting.AUTO_MAKE, ContainerUtilRt.<JComponent>newArrayList(myCbEnableAutomake, myEnableAutomakeLegendLabel));
|
||||
controls.put(Setting.PARALLEL_COMPILATION,
|
||||
ContainerUtilRt.<JComponent>newArrayList(myCbParallelCompilation, myParallelCompilationLegendLabel));
|
||||
controls.put(Setting.REBUILD_MODULE_ON_DEPENDENCY_CHANGE, ContainerUtilRt.<JComponent>newArrayList(myCbRebuildOnDependencyChange));
|
||||
controls.put(Setting.HEAP_SIZE, ContainerUtilRt.<JComponent>newArrayList(myHeapSizeLabel, myHeapSizeField));
|
||||
controls.put(Setting.COMPILER_VM_OPTIONS, ContainerUtilRt.<JComponent>newArrayList(myVMOptionsLabel, myVMOptionsField, mySharedVMOptionsLabel, mySharedVMOptionsField));
|
||||
controls.put(Setting.RESOURCE_PATTERNS, ContainerUtilRt.newArrayList(myResourcePatternsLabel, myResourcePatternsField, myPatternLegendLabel));
|
||||
controls.put(Setting.CLEAR_OUTPUT_DIR_ON_REBUILD, Collections.singleton(myCbClearOutputDirectory));
|
||||
controls.put(Setting.ADD_NOT_NULL_ASSERTIONS, Collections.singleton(myCbAssertNotNull));
|
||||
controls.put(Setting.AUTO_SHOW_FIRST_ERROR_IN_EDITOR, Collections.singleton(myCbAutoShowFirstError));
|
||||
controls.put(Setting.DISPLAY_NOTIFICATION_POPUP, Collections.singleton(myCbDisplayNotificationPopup));
|
||||
controls.put(Setting.AUTO_MAKE, ContainerUtilRt.newArrayList(myCbEnableAutomake, myEnableAutomakeLegendLabel));
|
||||
controls.put(Setting.PARALLEL_COMPILATION, ContainerUtilRt.newArrayList(myCbParallelCompilation, myParallelCompilationLegendLabel));
|
||||
controls.put(Setting.REBUILD_MODULE_ON_DEPENDENCY_CHANGE, ContainerUtilRt.newArrayList(myCbRebuildOnDependencyChange));
|
||||
controls.put(Setting.HEAP_SIZE, ContainerUtilRt.newArrayList(myHeapSizeLabel, myHeapSizeField));
|
||||
controls.put(Setting.COMPILER_VM_OPTIONS, ContainerUtilRt.newArrayList(myVMOptionsLabel, myVMOptionsField, mySharedVMOptionsLabel, mySharedVMOptionsField));
|
||||
|
||||
for (Setting setting : myDisabledSettings) {
|
||||
Collection<JComponent> components = controls.get(setting);
|
||||
@@ -189,7 +196,8 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
|
||||
if (PowerSaveMode.isEnabled()) {
|
||||
myEnableAutomakeLegendLabel.setText("(disabled in Power Save mode)");
|
||||
myEnableAutomakeLegendLabel.setFont(myEnableAutomakeLegendLabel.getFont().deriveFont(Font.BOLD));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
myEnableAutomakeLegendLabel.setText("(only works while not running / debugging)");
|
||||
myEnableAutomakeLegendLabel.setFont(myEnableAutomakeLegendLabel.getFont().deriveFont(Font.PLAIN));
|
||||
}
|
||||
|
||||
@@ -30,8 +30,6 @@ import com.intellij.util.ui.JBUI;
|
||||
import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
@@ -39,8 +37,6 @@ import javax.swing.table.TableModel;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
@@ -66,7 +62,6 @@ public class ProcessorProfilePanel extends JPanel {
|
||||
private JPanel myProcessorPanel;
|
||||
private JPanel myOptionsPanel;
|
||||
private OptionsTableModel myOptionsModel;
|
||||
private JLabel myWarninglabel;
|
||||
private JLabel myStoreGenSourcesLabel;
|
||||
private JLabel myProductionLabel;
|
||||
private JLabel myTestLabel;
|
||||
@@ -132,12 +127,6 @@ public class ProcessorProfilePanel extends JPanel {
|
||||
myGeneratedProductionDirField = new JTextField();
|
||||
myGeneratedTestsDirField = new JTextField();
|
||||
|
||||
myWarninglabel = new JLabel("<html>WARNING!<br>" +
|
||||
/*"All source files located in the generated sources output directory WILL BE EXCLUDED from annotation processing. " +*/
|
||||
"If option 'Clear output directory on rebuild' is enabled, " +
|
||||
"the entire contents of directories where generated sources are stored WILL BE CLEARED on rebuild.</html>");
|
||||
myWarninglabel.setFont(myWarninglabel.getFont().deriveFont(Font.BOLD));
|
||||
|
||||
add(myCbEnableProcessing,
|
||||
new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, JBUI.emptyInsets(), 0, 0));
|
||||
add(myRbClasspath,
|
||||
@@ -171,28 +160,16 @@ public class ProcessorProfilePanel extends JPanel {
|
||||
new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, JBUI.insetsTop(10), 0, 0));
|
||||
add(myOptionsTablePanel,
|
||||
new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, JBUI.insetsTop(10), 0, 0));
|
||||
add(myWarninglabel,
|
||||
new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, JBUI.insets(10, 5, 0, 0), 0, 0));
|
||||
|
||||
myRbClasspath.addItemListener(new ItemListener() {
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
myRbClasspath.addItemListener(e -> updateEnabledState());
|
||||
|
||||
myProcessorTable.getSelectionModel().addListSelectionListener(e -> {
|
||||
if (!e.getValueIsAdjusting()) {
|
||||
updateEnabledState();
|
||||
}
|
||||
});
|
||||
|
||||
myProcessorTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
if (!e.getValueIsAdjusting()) {
|
||||
updateEnabledState();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
myCbEnableProcessing.addItemListener(new ItemListener() {
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
updateEnabledState();
|
||||
}
|
||||
});
|
||||
myCbEnableProcessing.addItemListener(e -> updateEnabledState());
|
||||
|
||||
updateEnabledState();
|
||||
|
||||
@@ -273,7 +250,6 @@ public class ProcessorProfilePanel extends JPanel {
|
||||
myGeneratedTestsDirField.setEnabled(enabled);
|
||||
myRbRelativeToOutputRoot.setEnabled(enabled);
|
||||
myRbRelativeToContentRoot.setEnabled(enabled);
|
||||
myWarninglabel.setEnabled(enabled);
|
||||
myStoreGenSourcesLabel.setEnabled(enabled);
|
||||
myProductionLabel.setEnabled(enabled);
|
||||
myTestLabel.setEnabled(enabled);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.compiler.options;
|
||||
|
||||
import com.intellij.compiler.impl.rmiCompiler.RmicConfiguration;
|
||||
import com.intellij.compiler.server.BuildManager;
|
||||
import com.intellij.openapi.compiler.CompilerBundle;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
@@ -41,10 +42,12 @@ public class RmicConfigurable implements SearchableConfigurable, Configurable.No
|
||||
private JCheckBox myCbGenerateNoWarnings;
|
||||
private RawCommandLineEditor myAdditionalOptionsField;
|
||||
private final RmicCompilerOptions myRmicSettings;
|
||||
private final Project myProject;
|
||||
private JLabel myFieldLabel;
|
||||
|
||||
public RmicConfigurable(final Project project) {
|
||||
myRmicSettings = RmicConfiguration.getOptions(project);
|
||||
myProject = project;
|
||||
myCbEnabled.addItemListener(new ItemListener() {
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
setOptionsEnabled(e.getStateChange() == ItemEvent.SELECTED);
|
||||
@@ -89,11 +92,16 @@ public class RmicConfigurable implements SearchableConfigurable, Configurable.No
|
||||
}
|
||||
|
||||
public void apply() throws ConfigurationException {
|
||||
myRmicSettings.IS_EANABLED = myCbEnabled.isSelected();
|
||||
myRmicSettings.GENERATE_IIOP_STUBS = myCbGenerateIiopStubs.isSelected();
|
||||
myRmicSettings.DEBUGGING_INFO = myCbDebuggingInfo.isSelected();
|
||||
myRmicSettings.GENERATE_NO_WARNINGS = myCbGenerateNoWarnings.isSelected();
|
||||
myRmicSettings.ADDITIONAL_OPTIONS_STRING = myAdditionalOptionsField.getText();
|
||||
try {
|
||||
myRmicSettings.IS_EANABLED = myCbEnabled.isSelected();
|
||||
myRmicSettings.GENERATE_IIOP_STUBS = myCbGenerateIiopStubs.isSelected();
|
||||
myRmicSettings.DEBUGGING_INFO = myCbDebuggingInfo.isSelected();
|
||||
myRmicSettings.GENERATE_NO_WARNINGS = myCbGenerateNoWarnings.isSelected();
|
||||
myRmicSettings.ADDITIONAL_OPTIONS_STRING = myAdditionalOptionsField.getText();
|
||||
}
|
||||
finally {
|
||||
BuildManager.getInstance().clearState(myProject);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
|
||||
@@ -81,5 +81,9 @@ public class ValidationConfiguration implements PersistentStateComponent<Validat
|
||||
name = JpsCompilerValidationExcludeSerializer.COMPONENT_NAME,
|
||||
storages = @Storage(JpsCompilerValidationExcludeSerializer.CONFIG_FILE_NAME)
|
||||
)
|
||||
public static class ExcludedFromValidationConfiguration extends ExcludedEntriesConfiguration {}
|
||||
public static class ExcludedFromValidationConfiguration extends ExcludedEntriesConfiguration {
|
||||
public ExcludedFromValidationConfiguration() {
|
||||
super(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1166,17 +1166,6 @@ public class BuildManager implements Disposable {
|
||||
cmdLine.addParameters(args);
|
||||
}
|
||||
|
||||
//TODO[Dmitry Batkovich] should be replaced with the proper solution
|
||||
if (sdkVersion != null && sdkVersion.isAtLeast(JavaSdkVersion.JDK_1_9)) {
|
||||
cmdLine.addParameters("--add-exports", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED");
|
||||
cmdLine.addParameters("--add-exports", "jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED");
|
||||
cmdLine.addParameters("--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED");
|
||||
cmdLine.addParameters("--add-exports", "jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED");
|
||||
cmdLine.addParameters("--add-exports", "jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED");
|
||||
cmdLine.addParameters("--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED");
|
||||
cmdLine.addParameters("--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED");
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnnecessaryFullyQualifiedName")
|
||||
final Class<?> launcherClass = org.jetbrains.jps.cmdline.Launcher.class;
|
||||
|
||||
|
||||
+2
-2
@@ -46,7 +46,7 @@ public class ExcludeEntryDescription implements Disposable {
|
||||
return new ExcludeEntryDescription(getUrl(), myIncludeSubdirectories, myIsFile,parent);
|
||||
}
|
||||
|
||||
public void setPresentableUrl(String newUrl) {
|
||||
void setPresentableUrl(String newUrl) {
|
||||
myFilePointer = VirtualFilePointerManager.getInstance().create(VfsUtil.pathToUrl(FileUtil.toSystemIndependentName(newUrl)), myParentDisposable, null);
|
||||
final VirtualFile file = getVirtualFile();
|
||||
if (file != null) {
|
||||
@@ -70,7 +70,7 @@ public class ExcludeEntryDescription implements Disposable {
|
||||
return myIncludeSubdirectories;
|
||||
}
|
||||
|
||||
public void setIncludeSubdirectories(boolean includeSubdirectories) {
|
||||
void setIncludeSubdirectories(boolean includeSubdirectories) {
|
||||
myIncludeSubdirectories = includeSubdirectories;
|
||||
}
|
||||
|
||||
|
||||
+18
-2
@@ -24,6 +24,7 @@ import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -38,8 +39,13 @@ public class ExcludedEntriesConfiguration implements PersistentStateComponent<Ex
|
||||
@NonNls private static final String URL = "url";
|
||||
@NonNls private static final String INCLUDE_SUBDIRECTORIES = "includeSubdirectories";
|
||||
private final Collection<ExcludeEntryDescription> myExcludeEntryDescriptions = new LinkedHashSet<>();
|
||||
@Nullable private final ExcludedEntriesListener myEventPublisher;
|
||||
private ExcludeEntryDescription[] myCachedDescriptions = null;
|
||||
|
||||
public ExcludedEntriesConfiguration(@Nullable ExcludedEntriesListener eventPublisher) {
|
||||
myEventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ExcludeEntryDescription[] getExcludeEntryDescriptions() {
|
||||
if (myCachedDescriptions == null) {
|
||||
@@ -50,19 +56,29 @@ public class ExcludedEntriesConfiguration implements PersistentStateComponent<Ex
|
||||
|
||||
@Override
|
||||
public synchronized void addExcludeEntryDescription(ExcludeEntryDescription description) {
|
||||
myExcludeEntryDescriptions.add(description);
|
||||
if (myExcludeEntryDescriptions.add(description) && myEventPublisher != null) {
|
||||
myEventPublisher.onEntryAdded(description);
|
||||
}
|
||||
myCachedDescriptions = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void removeExcludeEntryDescription(ExcludeEntryDescription description) {
|
||||
myExcludeEntryDescriptions.remove(description);
|
||||
if (myExcludeEntryDescriptions.remove(description) && myEventPublisher != null) {
|
||||
myEventPublisher.onEntryRemoved(description);
|
||||
}
|
||||
myCachedDescriptions = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void removeAllExcludeEntryDescriptions() {
|
||||
ExcludeEntryDescription[] oldDescriptions = getExcludeEntryDescriptions();
|
||||
myExcludeEntryDescriptions.clear();
|
||||
if (myEventPublisher != null) {
|
||||
for (ExcludeEntryDescription description : oldDescriptions) {
|
||||
myEventPublisher.onEntryRemoved(description);
|
||||
}
|
||||
}
|
||||
myCachedDescriptions = null;
|
||||
}
|
||||
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 com.intellij.openapi.compiler.options;
|
||||
|
||||
import com.intellij.util.messages.Topic;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public interface ExcludedEntriesListener {
|
||||
Topic<ExcludedEntriesListener> TOPIC = Topic.create("Compiler's excluded entries modification notification", ExcludedEntriesListener.class);
|
||||
|
||||
default void onEntryAdded(@NotNull ExcludeEntryDescription description) {}
|
||||
|
||||
default void onEntryRemoved(@NotNull ExcludeEntryDescription description) {}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import com.sun.jdi.request.EventRequest;
|
||||
/**
|
||||
* @author egor
|
||||
*/
|
||||
public class ClassInstanceMethodFilter extends ConstructorStepMethodFilter implements ActionMethodFilter {
|
||||
public class ClassInstanceMethodFilter extends ConstructorStepMethodFilter {
|
||||
private final BreakpointStepMethodFilter myMethodFilter;
|
||||
|
||||
public ClassInstanceMethodFilter(PsiMethod psiMethod, Range<Integer> lines) {
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
|
||||
import com.intellij.debugger.requests.Requestor;
|
||||
import com.intellij.debugger.settings.DebuggerSettings;
|
||||
import com.intellij.debugger.ui.breakpoints.Breakpoint;
|
||||
import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
|
||||
import com.intellij.execution.configurations.RemoteConnection;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
@@ -93,16 +92,11 @@ public class DebugProcessEvents extends DebugProcessImpl {
|
||||
final Event event = descriptor.getSecond();
|
||||
final Breakpoint breakpoint = descriptor.getFirst();
|
||||
if (event instanceof LocatableEvent) {
|
||||
if (breakpoint instanceof LineBreakpoint && !((LineBreakpoint)breakpoint).isVisible()) {
|
||||
text = DebuggerBundle.message("status.stopped.at.cursor");
|
||||
try {
|
||||
text = breakpoint != null ? breakpoint.getEventMessage(((LocatableEvent)event)) : DebuggerBundle.message("status.generic.breakpoint.reached");
|
||||
}
|
||||
else {
|
||||
try {
|
||||
text = breakpoint != null? breakpoint.getEventMessage(((LocatableEvent)event)) : DebuggerBundle.message("status.generic.breakpoint.reached");
|
||||
}
|
||||
catch (InternalException e) {
|
||||
text = DebuggerBundle.message("status.generic.breakpoint.reached");
|
||||
}
|
||||
catch (InternalException e) {
|
||||
text = DebuggerBundle.message("status.generic.breakpoint.reached");
|
||||
}
|
||||
}
|
||||
else if (event instanceof VMStartEvent) {
|
||||
|
||||
@@ -753,8 +753,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
setRunToCursorBreakpoint(null);
|
||||
getRequestsManager().deleteRequest(runToCursorBreakpoint);
|
||||
if (runToCursorBreakpoint.isRestoreBreakpoints()) {
|
||||
final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
|
||||
breakpointManager.enableBreakpoints(this);
|
||||
DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager().enableBreakpoints(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1625,8 +1624,8 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
private RunToCursorCommand(SuspendContextImpl suspendContext, @NotNull XSourcePosition position, final boolean ignoreBreakpoints) {
|
||||
super(suspendContext);
|
||||
myIgnoreBreakpoints = ignoreBreakpoints;
|
||||
BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
|
||||
myRunToCursorBreakpoint = breakpointManager.addRunToCursorBreakpoint(position, ignoreBreakpoints);
|
||||
myRunToCursorBreakpoint =
|
||||
DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().addRunToCursorBreakpoint(position, ignoreBreakpoints);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1637,8 +1636,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
return;
|
||||
}
|
||||
if (myIgnoreBreakpoints) {
|
||||
final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
|
||||
breakpointManager.disableBreakpoints(DebugProcessImpl.this);
|
||||
DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().disableBreakpoints(DebugProcessImpl.this);
|
||||
}
|
||||
applyThreadFilter(getContextThread());
|
||||
final SuspendContextImpl context = getSuspendContext();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -23,4 +23,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
public interface MethodFilter {
|
||||
boolean locationMatches(DebugProcessImpl process, Location location) throws EvaluateException;
|
||||
@Nullable Range<Integer> getCallingExpressionLines();
|
||||
|
||||
default int onReached(SuspendContextImpl context, RequestHint hint) {
|
||||
return RequestHint.STOP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,13 +180,6 @@ public class RequestHint {
|
||||
}
|
||||
}
|
||||
|
||||
private int reached(MethodFilter filter, SuspendContextImpl context) {
|
||||
if (filter instanceof ActionMethodFilter) {
|
||||
return ((ActionMethodFilter)filter).onReached(context, this);
|
||||
}
|
||||
return STOP;
|
||||
}
|
||||
|
||||
protected boolean isSteppedOut() {
|
||||
return mySteppedOut;
|
||||
}
|
||||
@@ -203,7 +196,7 @@ public class RequestHint {
|
||||
!isTheSameFrame(context)
|
||||
) {
|
||||
myTargetMethodMatched = true;
|
||||
return reached(myMethodFilter, context);
|
||||
return myMethodFilter.onReached(context, this);
|
||||
}
|
||||
|
||||
if ((myDepth == StepRequest.STEP_OVER || myDepth == StepRequest.STEP_INTO) && myPosition != null) {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.debugger.memory.ui.ClassesTable;
|
||||
|
||||
public abstract class ClassesActionBase extends AnAction {
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(isEnabled(e));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
perform(e);
|
||||
}
|
||||
|
||||
protected boolean isEnabled(AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
return project != null && !project.isDisposed();
|
||||
}
|
||||
|
||||
protected abstract void perform(AnActionEvent e);
|
||||
|
||||
@Nullable
|
||||
protected ReferenceType getSelectedClass(AnActionEvent e) {
|
||||
return e.getData(ClassesTable.SELECTED_CLASS_KEY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
XDebugSession getDebugSession(AnActionEvent e) {
|
||||
return e.getData(ClassesTable.DEBUG_SESSION_KEY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.debugger.ui.impl.watch.NodeDescriptorProvider;
|
||||
import com.intellij.debugger.ui.tree.NodeDescriptor;
|
||||
import com.intellij.debugger.ui.tree.ValueDescriptor;
|
||||
import com.intellij.xdebugger.frame.XValue;
|
||||
import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.Value;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class DebuggerTreeAction extends XDebuggerTreeActionBase {
|
||||
@Nullable
|
||||
protected ObjectReference getObjectReference(@NotNull XValueNodeImpl node) {
|
||||
XValue valueContainer = node.getValueContainer();
|
||||
if (valueContainer instanceof NodeDescriptorProvider) {
|
||||
NodeDescriptor descriptor = ((NodeDescriptorProvider) valueContainer).getDescriptor();
|
||||
if (descriptor instanceof ValueDescriptor) {
|
||||
Value value = ((ValueDescriptor)descriptor).getValue();
|
||||
return value instanceof ObjectReference ? (ObjectReference) value : null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.debugger.memory.component.InstancesTracker;
|
||||
|
||||
public class EnableBackgroundTrackingAction extends ToggleAction{
|
||||
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
return project != null && InstancesTracker.getInstance(project).isBackgroundTrackingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
Project project = e.getProject();
|
||||
if (project != null) {
|
||||
InstancesTracker.getInstance(project).setBackgroundTackingEnabled(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.codeInsight.navigation.NavigationUtil;
|
||||
import com.intellij.debugger.engine.DebuggerUtils;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.sun.jdi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JumpToTypeSourceAction extends ClassesActionBase {
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled(AnActionEvent e) {
|
||||
final PsiClass psiClass = getPsiClass(e);
|
||||
|
||||
return super.isEnabled(e) && psiClass != null && psiClass.isPhysical();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void perform(AnActionEvent e) {
|
||||
final PsiClass psiClass = getPsiClass(e);
|
||||
if (psiClass != null) {
|
||||
NavigationUtil.activateFileWithPsiElement(psiClass);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiClass getPsiClass(AnActionEvent e) {
|
||||
ReferenceType selectedClass = getSelectedClass(e);
|
||||
XDebugSession session = getDebugSession(e);
|
||||
if (selectedClass == null || session == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ReferenceType targetClass = getObjectType(selectedClass);
|
||||
if (targetClass != null) {
|
||||
Project project = session.getProject();
|
||||
return DebuggerUtils
|
||||
.findClass(targetClass.name(), project, GlobalSearchScope.allScope(project));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ReferenceType getObjectType(@NotNull ReferenceType ref) {
|
||||
if (!(ref instanceof ArrayType)) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
String elementTypeName = ref.name().replace("[]", "");
|
||||
VirtualMachine vm = ref.virtualMachine();
|
||||
final List<ReferenceType> referenceTypes = vm.classesByName(elementTypeName);
|
||||
if (referenceTypes.size() == 1) {
|
||||
return referenceTypes.get(0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.debugger.memory.component.MemoryViewManager;
|
||||
|
||||
public class ShowClassesWithDiffAction extends ToggleAction {
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
return MemoryViewManager.getInstance().isNeedShowDiffOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
Project project = e.getProject();
|
||||
if (project != null) {
|
||||
MemoryViewManager.getInstance().setShowDiffOnly(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.debugger.memory.component.MemoryViewManager;
|
||||
|
||||
public class ShowClassesWithInstanceAction extends ToggleAction {
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
return MemoryViewManager.getInstance().isNeedShowInstancesOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
Project project = e.getProject();
|
||||
if (project != null) {
|
||||
MemoryViewManager.getInstance().setShowWithInstancesOnly(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
|
||||
abstract class ShowInstancesAction extends ClassesActionBase {
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
boolean enabled = isEnabled(e);
|
||||
if (enabled) {
|
||||
e.getPresentation().setText(String.format("%s (%d)", getLabel(), getInstancesCount(e)));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract String getLabel();
|
||||
|
||||
protected abstract int getInstancesCount(AnActionEvent e);
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebuggerManager;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.intellij.debugger.memory.ui.InstancesWindow;
|
||||
|
||||
public class ShowInstancesByClassAction extends DebuggerTreeAction {
|
||||
@Override
|
||||
protected boolean isEnabled(@NotNull XValueNodeImpl node, @NotNull AnActionEvent e) {
|
||||
ObjectReference ref = getObjectReference(node);
|
||||
if(ref != null) {
|
||||
String text = String.format("Show %s Objects...", StringUtil.getShortName(ref.referenceType().name()));
|
||||
e.getPresentation().setText(text);
|
||||
}
|
||||
|
||||
return ref != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
if (project != null) {
|
||||
XDebugSession debugSession = XDebuggerManager.getInstance(project).getCurrentSession();
|
||||
ObjectReference ref = getObjectReference(node);
|
||||
if(debugSession != null && ref != null){
|
||||
ReferenceType referenceType = ref.referenceType();
|
||||
new InstancesWindow(debugSession, referenceType::instances, referenceType.name()).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import com.intellij.debugger.memory.ui.ClassesTable;
|
||||
import com.intellij.debugger.memory.ui.InstancesWindow;
|
||||
|
||||
public class ShowInstancesFromClassesViewAction extends ShowInstancesAction {
|
||||
private static final String POPUP_ELEMENT_LABEL = "Show Instances";
|
||||
@Override
|
||||
protected boolean isEnabled(AnActionEvent e) {
|
||||
return super.isEnabled(e) && getSelectedClass(e) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void perform(AnActionEvent e) {
|
||||
XDebugSession debugSession = getDebugSession(e);
|
||||
ReferenceType selectedClass = getSelectedClass(e);
|
||||
if (debugSession != null && selectedClass != null) {
|
||||
new InstancesWindow(debugSession, selectedClass::instances, selectedClass.name()).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLabel() {
|
||||
return POPUP_ELEMENT_LABEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getInstancesCount(AnActionEvent e) {
|
||||
ClassesTable.ReferenceCountProvider countProvider = e.getData(ClassesTable.REF_COUNT_PROVIDER_KEY);
|
||||
ReferenceType selectedClass = getSelectedClass(e);
|
||||
if (countProvider == null || selectedClass == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return countProvider.getTotalCount(selectedClass);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import com.intellij.debugger.memory.utils.InstancesProvider;
|
||||
import com.intellij.debugger.memory.ui.ClassesTable;
|
||||
import com.intellij.debugger.memory.ui.InstancesWindow;
|
||||
|
||||
public class ShowNewInstancesAction extends ShowInstancesAction {
|
||||
private static final String POPUP_ELEMENT_LABEL = "Show New Instances";
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled(AnActionEvent e) {
|
||||
XDebugSession session = getDebugSession(e);
|
||||
ReferenceType selectedClass = getSelectedClass(e);
|
||||
InstancesProvider provider = e.getData(ClassesTable.NEW_INSTANCES_PROVIDER_KEY);
|
||||
return super.isEnabled(e) && session != null && selectedClass != null && provider != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLabel() {
|
||||
return POPUP_ELEMENT_LABEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getInstancesCount(AnActionEvent e) {
|
||||
ClassesTable.ReferenceCountProvider countProvider = e.getData(ClassesTable.REF_COUNT_PROVIDER_KEY);
|
||||
ReferenceType selectedClass = getSelectedClass(e);
|
||||
if (countProvider == null || selectedClass == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return countProvider.getNewInstancesCount(selectedClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void perform(AnActionEvent e) {
|
||||
XDebugSession session = getDebugSession(e);
|
||||
ReferenceType selectedClass = getSelectedClass(e);
|
||||
InstancesProvider provider = e.getData(ClassesTable.NEW_INSTANCES_PROVIDER_KEY);
|
||||
if (selectedClass != null && provider != null && session != null) {
|
||||
new InstancesWindow(session, provider, selectedClass.name()).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
||||
import com.intellij.debugger.memory.component.MemoryViewManager;
|
||||
|
||||
public class ShowTrackedAction extends ToggleAction {
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
return MemoryViewManager.getInstance().isNeedShowTrackedOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
if (e.getProject() != null) {
|
||||
MemoryViewManager.getInstance().setShowTrackedOnly(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action.tracking;
|
||||
|
||||
import com.intellij.debugger.DebuggerManager;
|
||||
import com.intellij.debugger.memory.action.DebuggerTreeAction;
|
||||
import com.intellij.debugger.memory.ui.StackFramePopup;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebuggerManager;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.debugger.memory.component.CreationPositionTracker;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
import com.intellij.debugger.memory.ui.InstancesTree;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JumpToAllocationSourceAction extends DebuggerTreeAction {
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setVisible(getStack(e) != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
List<StackFrameItem> stack = getStack(e);
|
||||
if(project != null && stack != null) {
|
||||
XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession();
|
||||
if(session != null) {
|
||||
GlobalSearchScope searchScope = DebuggerManager.getInstance(project)
|
||||
.getDebugProcess(session.getDebugProcess().getProcessHandler()).getSearchScope();
|
||||
new StackFramePopup(project, stack, searchScope).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<StackFrameItem> getStack(AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
XValueNodeImpl selectedNode = getSelectedNode(e.getDataContext());
|
||||
ObjectReference ref = selectedNode != null ? getObjectReference(selectedNode) : null;
|
||||
if(project == null || ref == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
XDebugSession session = e.getData(InstancesTree.DEBUG_SESSION_DATA_KEY);
|
||||
CreationPositionTracker tracker = CreationPositionTracker.getInstance(project);
|
||||
return session == null || tracker == null ? null : tracker.getStack(session, ref);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.action.tracking;
|
||||
|
||||
import com.intellij.debugger.memory.component.InstancesTracker;
|
||||
import com.intellij.debugger.memory.tracking.TrackingType;
|
||||
import com.intellij.debugger.memory.ui.ClassesTable;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.sun.jdi.ArrayType;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class TrackInstancesToggleAction extends ToggleAction {
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
ReferenceType selectedClass = getSelectedClass(e);
|
||||
if (selectedClass instanceof ArrayType) {
|
||||
e.getPresentation().setEnabled(false);
|
||||
} else {
|
||||
super.update(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
ReferenceType selectedClass = getSelectedClass(e);
|
||||
XDebugSession debugSession = getDebugSession(e);
|
||||
if (debugSession != null && selectedClass != null) {
|
||||
InstancesTracker tracker = InstancesTracker.getInstance(debugSession.getProject());
|
||||
return tracker.isTracked(selectedClass.name());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
ReferenceType selectedClass = getSelectedClass(e);
|
||||
XDebugSession debugSession = getDebugSession(e);
|
||||
if (selectedClass != null && debugSession != null) {
|
||||
InstancesTracker tracker = InstancesTracker.getInstance(debugSession.getProject());
|
||||
boolean isAlreadyTracked = tracker.isTracked(selectedClass.name());
|
||||
|
||||
if (isAlreadyTracked && !state) {
|
||||
tracker.remove(selectedClass.name());
|
||||
}
|
||||
|
||||
if (!isAlreadyTracked && state) {
|
||||
tracker.add(selectedClass.name(), TrackingType.CREATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ReferenceType getSelectedClass(AnActionEvent e) {
|
||||
return e.getData(ClassesTable.SELECTED_CLASS_KEY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static XDebugSession getDebugSession(AnActionEvent e) {
|
||||
return e.getData(ClassesTable.DEBUG_SESSION_KEY);
|
||||
}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.component;
|
||||
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
import com.intellij.openapi.components.AbstractProjectComponent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebugSessionListener;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CreationPositionTracker extends AbstractProjectComponent {
|
||||
/**
|
||||
* Stores all tracked instance for each debug session.
|
||||
*/
|
||||
private final ConcurrentHashMap<XDebugSession, Map<ObjectReference, List<StackFrameItem>>>
|
||||
mySession2Reference2Stack = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentHashMap<XDebugSession, Map<ObjectReference, List<StackFrameItem>>>
|
||||
myPinnedSession2Reference2Stack = new ConcurrentHashMap<>();
|
||||
|
||||
public CreationPositionTracker(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CreationPositionTracker getInstance(@NotNull Project project) {
|
||||
return project.isDisposed() ? null : project.getComponent(CreationPositionTracker.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<StackFrameItem> getStack(@NotNull XDebugSession session, @NotNull ObjectReference ref) {
|
||||
List<StackFrameItem> stack = extract(mySession2Reference2Stack, session, ref);
|
||||
return stack != null ? stack : extract(myPinnedSession2Reference2Stack, session, ref);
|
||||
}
|
||||
|
||||
public void addStack(@NotNull XDebugSession session, @NotNull ObjectReference ref,
|
||||
@NotNull List<StackFrameItem> stack) {
|
||||
if (!mySession2Reference2Stack.containsKey(session)) {
|
||||
mySession2Reference2Stack.put(session, new ConcurrentHashMap<>());
|
||||
session.addSessionListener(new XDebugSessionListener() {
|
||||
@Override
|
||||
public void sessionStopped() {
|
||||
mySession2Reference2Stack.remove(session);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mySession2Reference2Stack.get(session).put(ref, stack);
|
||||
}
|
||||
|
||||
public void releaseBySession(@NotNull XDebugSession session) {
|
||||
if(mySession2Reference2Stack.containsKey(session)) {
|
||||
mySession2Reference2Stack.put(session, new ConcurrentHashMap<>());
|
||||
}
|
||||
}
|
||||
|
||||
public void unpinStacks(@NotNull XDebugSession session, @NotNull ReferenceType ref) {
|
||||
Map<ObjectReference, List<StackFrameItem>> ref2Stack = myPinnedSession2Reference2Stack.getOrDefault(session, null);
|
||||
if (ref2Stack != null) {
|
||||
Iterator<ObjectReference> iterator = ref2Stack.keySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
ObjectReference reference = iterator.next();
|
||||
if (ref.equals(reference.referenceType())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (ref2Stack.isEmpty()) {
|
||||
myPinnedSession2Reference2Stack.remove(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void pinStacks(@NotNull XDebugSession session, @NotNull ReferenceType ref) {
|
||||
Map<ObjectReference, List<StackFrameItem>> ref2Stack = mySession2Reference2Stack.getOrDefault(session, null);
|
||||
if (ref2Stack != null) {
|
||||
Map<ObjectReference, List<StackFrameItem>> ref2StacksByReferenceType = ref2Stack.entrySet().stream()
|
||||
.filter(entry -> ref.equals(entry.getKey().referenceType()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
myPinnedSession2Reference2Stack.put(session, ref2StacksByReferenceType);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static<T> T extract(@NotNull Map<XDebugSession, Map<ObjectReference, T>> map,
|
||||
@NotNull XDebugSession session, @NotNull ObjectReference ref) {
|
||||
Map<ObjectReference, T> ref2something = map.getOrDefault(session, null);
|
||||
if(ref2something != null) {
|
||||
return ref2something.getOrDefault(ref, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.component;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.xmlb.annotations.AbstractCollection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.debugger.memory.event.InstancesTrackerListener;
|
||||
import com.intellij.debugger.memory.tracking.TrackingType;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@State(name = "InstancesTracker", storages = @Storage(StoragePathMacros.WORKSPACE_FILE))
|
||||
public class InstancesTracker extends AbstractProjectComponent
|
||||
implements PersistentStateComponent<InstancesTracker.MyState> {
|
||||
private final EventDispatcher<InstancesTrackerListener> myDispatcher =
|
||||
EventDispatcher.create(InstancesTrackerListener.class);
|
||||
private MyState myState = new MyState();
|
||||
|
||||
public InstancesTracker(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
public static InstancesTracker getInstance(@NotNull Project project) {
|
||||
return project.getComponent(InstancesTracker.class);
|
||||
}
|
||||
|
||||
public boolean isTracked(@NotNull String className) {
|
||||
return myState.classes.containsKey(className);
|
||||
}
|
||||
|
||||
public boolean isBackgroundTrackingEnabled() {
|
||||
return myState.isBackgroundTrackingEnabled;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TrackingType getTrackingType(@NotNull String className) {
|
||||
return myState.classes.getOrDefault(className, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, TrackingType> getTrackedClasses() {
|
||||
return new HashMap<>(myState.classes);
|
||||
}
|
||||
|
||||
public void add(@NotNull String name, @NotNull TrackingType type) {
|
||||
if (type.equals(myState.classes.getOrDefault(name, null))) {
|
||||
return;
|
||||
}
|
||||
|
||||
myState.classes.put(name, type);
|
||||
myDispatcher.getMulticaster().classChanged(name, type);
|
||||
}
|
||||
|
||||
public void remove(@NotNull String name) {
|
||||
TrackingType removed = myState.classes.remove(name);
|
||||
if (removed != null) {
|
||||
myDispatcher.getMulticaster().classRemoved(name);
|
||||
}
|
||||
}
|
||||
|
||||
public void addTrackerListener(@NotNull InstancesTrackerListener listener, @NotNull Disposable parentDisposable) {
|
||||
myDispatcher.addListener(listener, parentDisposable);
|
||||
}
|
||||
|
||||
public void setBackgroundTackingEnabled(boolean state) {
|
||||
boolean oldState = myState.isBackgroundTrackingEnabled;
|
||||
if(state != oldState) {
|
||||
myState.isBackgroundTrackingEnabled = state;
|
||||
myDispatcher.getMulticaster().backgroundTrackingValueChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public MyState getState() {
|
||||
return new MyState(myState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(MyState state) {
|
||||
myState = new MyState(state);
|
||||
}
|
||||
|
||||
static class MyState {
|
||||
boolean isBackgroundTrackingEnabled = false;
|
||||
|
||||
@NotNull
|
||||
@AbstractCollection(surroundWithTag = false, elementTypes = {Map.Entry.class})
|
||||
final Map<String, TrackingType> classes = new ConcurrentHashMap<>();
|
||||
|
||||
MyState() {
|
||||
}
|
||||
|
||||
MyState(@NotNull MyState state) {
|
||||
isBackgroundTrackingEnabled = state.isBackgroundTrackingEnabled;
|
||||
for (Map.Entry<String, TrackingType> classState : state.classes.entrySet()) {
|
||||
classes.put(classState.getKey(), classState.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.component;
|
||||
|
||||
import com.intellij.debugger.memory.event.MemoryViewManagerListener;
|
||||
import com.intellij.debugger.memory.toolwindow.MemoryViewToolWindowFactory;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@State(name = "MemoryViewSettings", storages = @Storage("memory.view.xml"))
|
||||
public class MemoryViewManager extends ApplicationComponent.Adapter
|
||||
implements PersistentStateComponent<MemoryViewManagerState> {
|
||||
private final EventDispatcher<MemoryViewManagerListener> myDispatcher =
|
||||
EventDispatcher.create(MemoryViewManagerListener.class);
|
||||
private MemoryViewManagerState myState = new MemoryViewManagerState();
|
||||
|
||||
public static MemoryViewManager getInstance() {
|
||||
return ApplicationManager.getApplication().getComponent(MemoryViewManager.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public MemoryViewManagerState getState() {
|
||||
return new MemoryViewManagerState(myState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(MemoryViewManagerState state) {
|
||||
if (state == null) {
|
||||
state = new MemoryViewManagerState();
|
||||
}
|
||||
|
||||
myState = state;
|
||||
fireStateChanged();
|
||||
}
|
||||
|
||||
public void setShowDiffOnly(boolean value) {
|
||||
if (myState.isShowWithDiffOnly != value) {
|
||||
myState.isShowWithDiffOnly = value;
|
||||
fireStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void setShowWithInstancesOnly(boolean value) {
|
||||
if (myState.isShowWithInstancesOnly != value) {
|
||||
myState.isShowWithInstancesOnly = value;
|
||||
fireStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void setShowTrackedOnly(boolean value) {
|
||||
if (myState.isShowTrackedOnly != value) {
|
||||
myState.isShowTrackedOnly = value;
|
||||
fireStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNeedShowDiffOnly() {
|
||||
return myState.isShowWithDiffOnly;
|
||||
}
|
||||
|
||||
public boolean isNeedShowInstancesOnly() {
|
||||
return myState.isShowWithInstancesOnly;
|
||||
}
|
||||
|
||||
public boolean isNeedShowTrackedOnly() {
|
||||
return myState.isShowTrackedOnly;
|
||||
}
|
||||
|
||||
public void addMemoryViewManagerListener(MemoryViewManagerListener listener, @NotNull Disposable parentDisposable) {
|
||||
myDispatcher.addListener(listener, parentDisposable);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ToolWindow getToolWindow(Project project) {
|
||||
return ToolWindowManager.getInstance(project).getToolWindow(MemoryViewToolWindowFactory.TOOL_WINDOW_ID);
|
||||
}
|
||||
|
||||
private void fireStateChanged() {
|
||||
myDispatcher.getMulticaster().stateChanged(new MemoryViewManagerState(myState));
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.component;
|
||||
|
||||
public final class MemoryViewManagerState {
|
||||
public boolean isShowWithInstancesOnly = true;
|
||||
public boolean isShowWithDiffOnly = false;
|
||||
public boolean isShowTrackedOnly = false;
|
||||
|
||||
MemoryViewManagerState() {
|
||||
}
|
||||
|
||||
MemoryViewManagerState(MemoryViewManagerState other) {
|
||||
isShowWithInstancesOnly = other.isShowWithInstancesOnly;
|
||||
isShowWithDiffOnly = other.isShowWithDiffOnly;
|
||||
isShowTrackedOnly = other.isShowTrackedOnly;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.event;
|
||||
|
||||
import com.intellij.debugger.memory.tracking.TrackingType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
public interface InstancesTrackerListener extends EventListener {
|
||||
default void classChanged(@NotNull String name, @NotNull TrackingType type) {
|
||||
}
|
||||
|
||||
default void classRemoved(@NotNull String name) {
|
||||
}
|
||||
|
||||
default void backgroundTrackingValueChanged(boolean newState) {
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.event;
|
||||
|
||||
import com.intellij.debugger.memory.component.MemoryViewManagerState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface MemoryViewManagerListener extends EventListener {
|
||||
void stateChanged(@NotNull MemoryViewManagerState state);
|
||||
}
|
||||
+14
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
@@ -13,15 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.debugger.memory.filtering;
|
||||
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api.statements;
|
||||
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrNamedElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* author ven
|
||||
* @author Vitaliy.Bibaev
|
||||
*/
|
||||
public interface GrTopLevelDefinition extends GrNamedElement, GrTopStatement {
|
||||
GrTopLevelDefinition[] EMPTY_ARRAY = new GrTopLevelDefinition[0];
|
||||
public interface CheckingResult {
|
||||
@NotNull
|
||||
Result getResult();
|
||||
|
||||
@NotNull
|
||||
String getFailureDescription();
|
||||
|
||||
enum Result {
|
||||
MATCH, NO_MATCH, ERROR
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.filtering;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Vitaliy.Bibaev
|
||||
*/
|
||||
public class CheckingResultImpl implements CheckingResult {
|
||||
public static final CheckingResult SUCCESS = new CheckingResultImpl(CheckingResultImpl.Result.MATCH, "");
|
||||
public static final CheckingResult FAIL = new CheckingResultImpl(CheckingResultImpl.Result.NO_MATCH, "");
|
||||
|
||||
private final Result myResult;
|
||||
private final String myDescription;
|
||||
|
||||
private CheckingResultImpl(@NotNull Result result, @NotNull String description) {
|
||||
myResult = result;
|
||||
myDescription = description;
|
||||
}
|
||||
|
||||
public static CheckingResult error(@NotNull String description) {
|
||||
return new CheckingResultImpl(Result.ERROR, description);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Result getResult() {
|
||||
return myResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFailureDescription() {
|
||||
return myDescription;
|
||||
}
|
||||
}
|
||||
+11
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -13,28 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.concurrency;
|
||||
package com.intellij.debugger.memory.filtering;
|
||||
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Executes given runnable exactly once.
|
||||
* <p/>
|
||||
* Author: dmitrylomov
|
||||
* @author Vitaliy.Bibaev
|
||||
*/
|
||||
public class DoOnce {
|
||||
private final AtomicReference<Runnable> myRunnable;
|
||||
public interface ConditionChecker {
|
||||
CheckingResult check(@NotNull ObjectReference ref);
|
||||
|
||||
public DoOnce(@NotNull Runnable runnable) {
|
||||
myRunnable = new AtomicReference<Runnable>(runnable);
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
Runnable runnable = myRunnable.getAndSet(null);
|
||||
if (runnable != null) {
|
||||
runnable.run();
|
||||
ConditionChecker ALL_MATCHED_CHECKER = new ConditionChecker() {
|
||||
@Override
|
||||
public CheckingResult check(@NotNull ObjectReference ref) {
|
||||
return CheckingResultImpl.SUCCESS;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.filtering;
|
||||
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
|
||||
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
|
||||
import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
|
||||
import com.intellij.debugger.ui.tree.render.CachedEvaluator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.xdebugger.XExpression;
|
||||
import com.sun.jdi.BooleanValue;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.Value;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* @author Vitaliy.Bibaev
|
||||
*/
|
||||
public class ConditionCheckerImpl implements ConditionChecker {
|
||||
private final DebugProcessImpl myDebugProcess;
|
||||
private final MyCachedEvaluator myEvaluator;
|
||||
private final AtomicReference<CheckingResult> myResultReference = new AtomicReference<>();
|
||||
|
||||
public ConditionCheckerImpl(@NotNull DebugProcessImpl debugProcess,
|
||||
@Nullable XExpression expression,
|
||||
@NotNull String className) {
|
||||
myDebugProcess = debugProcess;
|
||||
myEvaluator = new MyCachedEvaluator(myDebugProcess.getProject(), className);
|
||||
myEvaluator.setReferenceExpression(TextWithImportsImpl.fromXExpression(expression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CheckingResult check(@NotNull ObjectReference ref) {
|
||||
myDebugProcess.getManagerThread().invokeAndWait(new MyCheckerCommand(ref));
|
||||
return myResultReference.get();
|
||||
}
|
||||
|
||||
private class MyCheckerCommand extends DebuggerContextCommandImpl {
|
||||
private final ObjectReference myReference;
|
||||
|
||||
protected MyCheckerCommand(@NotNull ObjectReference ref) {
|
||||
super(myDebugProcess.getDebuggerContext());
|
||||
myReference = ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Priority getPriority() {
|
||||
return Priority.LOWEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void threadAction(@NotNull SuspendContextImpl suspendContext) {
|
||||
ExpressionEvaluator evaluator;
|
||||
try {
|
||||
evaluator = myEvaluator.getEvaluator();
|
||||
Value result =
|
||||
evaluator.evaluate(new EvaluationContextImpl(suspendContext, suspendContext.getFrameProxy(), myReference));
|
||||
if (result instanceof BooleanValue && ((BooleanValue)result).value()) {
|
||||
myResultReference.set(CheckingResultImpl.SUCCESS);
|
||||
}
|
||||
else {
|
||||
myResultReference.set(CheckingResultImpl.FAIL);
|
||||
}
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
myResultReference.set(CheckingResultImpl.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyCachedEvaluator extends CachedEvaluator {
|
||||
private final Project myProject;
|
||||
private final String myClassName;
|
||||
|
||||
public MyCachedEvaluator(@NotNull Project project, @NotNull String className) {
|
||||
super();
|
||||
myProject = project;
|
||||
myClassName = className;
|
||||
}
|
||||
|
||||
ExpressionEvaluator getEvaluator() throws EvaluateException {
|
||||
return getEvaluator(myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getClassName() {
|
||||
return myClassName;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-4
@@ -13,11 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.debugger.engine;
|
||||
package com.intellij.debugger.memory.filtering;
|
||||
|
||||
/**
|
||||
* @author egor
|
||||
* @author Vitaliy.Bibaev
|
||||
*/
|
||||
public interface ActionMethodFilter {
|
||||
int onReached(SuspendContextImpl context, RequestHint hint);
|
||||
public enum FilteringResult {
|
||||
ALL_CHECKED,
|
||||
|
||||
INTERRUPTED,
|
||||
|
||||
LIMIT_REACHED
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.filtering;
|
||||
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.xdebugger.XExpression;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Vitaliy.Bibaev
|
||||
*/
|
||||
public class FilteringTask implements Runnable {
|
||||
private final List<ObjectReference> myReferences;
|
||||
private final ConditionChecker myChecker;
|
||||
private final FilteringTaskCallback myCallback;
|
||||
|
||||
private volatile boolean myIsCancelled = false;
|
||||
|
||||
public FilteringTask(@NotNull ReferenceType referenceType, @NotNull DebugProcessImpl debugProcess,
|
||||
@NotNull XExpression expression, @NotNull List<ObjectReference> references,
|
||||
@NotNull FilteringTaskCallback callback) {
|
||||
myChecker = StringUtil.isEmptyOrSpaces(expression.getExpression())
|
||||
? ConditionChecker.ALL_MATCHED_CHECKER
|
||||
: new ConditionCheckerImpl(debugProcess, expression, referenceType.name());
|
||||
myReferences = references;
|
||||
myCallback = callback;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
myIsCancelled = true;
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return myIsCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
myCallback.started(myReferences.size());
|
||||
int proceedCount;
|
||||
for (proceedCount = 0; proceedCount < myReferences.size() && !myIsCancelled; proceedCount++) {
|
||||
ObjectReference ref = myReferences.get(proceedCount);
|
||||
CheckingResult result = myChecker.check(ref);
|
||||
FilteringTaskCallback.Action action = FilteringTaskCallback.Action.CONTINUE;
|
||||
switch (result.getResult()) {
|
||||
case MATCH:
|
||||
action = myCallback.matched(ref);
|
||||
break;
|
||||
case NO_MATCH:
|
||||
action = myCallback.notMatched(ref);
|
||||
break;
|
||||
case ERROR:
|
||||
action = myCallback.error(ref, result.getFailureDescription());
|
||||
break;
|
||||
}
|
||||
|
||||
if (action == FilteringTaskCallback.Action.STOP) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FilteringResult reason = myIsCancelled
|
||||
? FilteringResult.INTERRUPTED
|
||||
: proceedCount == myReferences.size()
|
||||
? FilteringResult.ALL_CHECKED
|
||||
: FilteringResult.LIMIT_REACHED;
|
||||
|
||||
myCallback.completed(reason);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.filtering;
|
||||
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Vitaliy.Bibaev
|
||||
*/
|
||||
public interface FilteringTaskCallback {
|
||||
void started(int totalCount);
|
||||
|
||||
@NotNull
|
||||
Action matched(@NotNull ObjectReference ref);
|
||||
|
||||
@NotNull
|
||||
Action notMatched(@NotNull ObjectReference ref);
|
||||
|
||||
@NotNull
|
||||
Action error(@NotNull ObjectReference ref, @NotNull String description);
|
||||
|
||||
void completed(@NotNull FilteringResult reason);
|
||||
|
||||
enum Action {
|
||||
STOP, CONTINUE
|
||||
}
|
||||
}
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.toolwindow;
|
||||
|
||||
import com.intellij.debugger.memory.component.MemoryViewManager;
|
||||
import com.intellij.debugger.memory.ui.ClassesFilteredView;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
import com.intellij.execution.ui.RunContentManager;
|
||||
import com.intellij.execution.ui.RunContentWithExecutorListener;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowFactory;
|
||||
import com.intellij.openapi.wm.ex.ToolWindowEx;
|
||||
import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter;
|
||||
import com.intellij.openapi.wm.impl.ToolWindowImpl;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.intellij.xdebugger.XDebugProcess;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebuggerManager;
|
||||
import com.intellij.xdebugger.XDebuggerManagerListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware {
|
||||
private static final Logger LOG = Logger.getInstance(ClassesFilteredView.class);
|
||||
public final static String TOOL_WINDOW_ID = "Memory View";
|
||||
|
||||
private final JComponent myEmptyContent;
|
||||
private final JComponent myMemoryViewNotSupportedContent;
|
||||
|
||||
private final Map<XDebugSession, ClassesFilteredView> myMemoryViews = new ConcurrentHashMap<>();
|
||||
|
||||
@Nullable
|
||||
private ClassesFilteredView myCurrentView = null;
|
||||
|
||||
{
|
||||
myEmptyContent = new JBLabel("Run debugging to see loaded classes", SwingConstants.CENTER);
|
||||
myMemoryViewNotSupportedContent = new JBLabel("The Memory View not available for this session",
|
||||
SwingConstants.CENTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
|
||||
MessageBusConnection connection = project.getMessageBus().connect(project);
|
||||
connection.subscribe(XDebuggerManager.TOPIC, new MyDebuggerStatusChangedListener());
|
||||
connection.subscribe(RunContentManager.TOPIC, new RunContentWithExecutorListener() {
|
||||
@Override
|
||||
public void contentSelected(@Nullable RunContentDescriptor descriptor, @NotNull Executor executor) {
|
||||
ApplicationManager.getApplication().invokeLater(() -> updateCurrentMemoryView(project, toolWindow));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contentRemoved(@Nullable RunContentDescriptor descriptor, @NotNull Executor executor) {
|
||||
ApplicationManager.getApplication().invokeLater(() -> updateCurrentMemoryView(project, toolWindow));
|
||||
}
|
||||
});
|
||||
|
||||
((ToolWindowImpl)toolWindow).getToolWindowManager()
|
||||
.addToolWindowManagerListener(new ToolWindowManagerAdapter() {
|
||||
@Override
|
||||
public void stateChanged() {
|
||||
if (!myMemoryViews.isEmpty() && !toolWindow.isDisposed()) {
|
||||
myMemoryViews.values().forEach(classesFilteredView ->
|
||||
classesFilteredView.setActive(toolWindow.isVisible()));
|
||||
}
|
||||
}
|
||||
}, project);
|
||||
|
||||
final ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction("MemoryView.SettingsPopupActionGroup");
|
||||
|
||||
((ToolWindowEx)toolWindow).setAdditionalGearActions(group);
|
||||
toolWindow.getComponent().setLayout(new BorderLayout());
|
||||
|
||||
for (XDebugSession session : XDebuggerManager.getInstance(project).getDebugSessions()) {
|
||||
addNewSession(session);
|
||||
}
|
||||
|
||||
updateCurrentMemoryView(project, toolWindow);
|
||||
}
|
||||
|
||||
private void addNewSession(@NotNull XDebugSession session) {
|
||||
LOG.assertTrue(SwingUtilities.isEventDispatchThread());
|
||||
ToolWindow toolWindow = getToolWindow(session.getProject());
|
||||
if (!myMemoryViews.containsKey(session)) {
|
||||
try {
|
||||
ClassesFilteredView newView = new ClassesFilteredView(session);
|
||||
newView.setActive(toolWindow != null && toolWindow.isVisible());
|
||||
myMemoryViews.put(session, newView);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.warn("Cannot create new instance of the memory view. " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeSession(@NotNull XDebugSession session) {
|
||||
ClassesFilteredView removed = myMemoryViews.remove(session);
|
||||
if (removed != null) {
|
||||
Disposer.dispose(removed);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCurrentMemoryView(@NotNull Project project, @NotNull ToolWindow toolWindow) {
|
||||
if (!project.isDisposed()) {
|
||||
XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession();
|
||||
if (session != null) {
|
||||
ClassesFilteredView view;
|
||||
if (myMemoryViews.containsKey(session)) {
|
||||
view = myMemoryViews.get(session);
|
||||
replaceToolWindowContent(toolWindow, view);
|
||||
}
|
||||
else {
|
||||
view = null;
|
||||
replaceToolWindowContent(toolWindow, myMemoryViewNotSupportedContent);
|
||||
}
|
||||
|
||||
if (myCurrentView != null) {
|
||||
myCurrentView.setActive(false);
|
||||
}
|
||||
|
||||
myCurrentView = view;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
replaceToolWindowContent(toolWindow, myEmptyContent);
|
||||
}
|
||||
|
||||
private static void replaceToolWindowContent(@NotNull ToolWindow toolWindow, JComponent comp) {
|
||||
LOG.assertTrue(SwingUtilities.isEventDispatchThread());
|
||||
JComponent toolWindowComp = toolWindow.getComponent();
|
||||
toolWindowComp.removeAll();
|
||||
toolWindowComp.add(comp);
|
||||
toolWindowComp.repaint();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ToolWindow getToolWindow(@NotNull Project project) {
|
||||
return MemoryViewManager.getInstance().getToolWindow(project);
|
||||
}
|
||||
|
||||
public static class Condition implements com.intellij.openapi.util.Condition<Project> {
|
||||
@Override
|
||||
public boolean value(Project project) {
|
||||
MessageBusConnection connection = project.getMessageBus().connect(project);
|
||||
connection.subscribe(XDebuggerManager.TOPIC, new XDebuggerManagerListener() {
|
||||
@Override
|
||||
public void processStarted(@NotNull XDebugProcess debugProcess) {
|
||||
updateIcon(debugProcess.getSession().getProject(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processStopped(@NotNull XDebugProcess debugProcess) {
|
||||
Project project = debugProcess.getSession().getProject();
|
||||
boolean enabled = Arrays.stream(XDebuggerManager.getInstance(project)
|
||||
.getDebugSessions()).anyMatch(session -> !session.getDebugProcess().equals(debugProcess));
|
||||
updateIcon(project, enabled);
|
||||
}
|
||||
|
||||
private void updateIcon(@NotNull Project project, boolean enabled) {
|
||||
ToolWindow toolWindow = MemoryViewManager.getInstance().getToolWindow(project);
|
||||
if (toolWindow != null) {
|
||||
Icon icon = enabled ? AllIcons.Debugger.MemoryView.ToolWindowEnabled : AllIcons.Debugger.MemoryView.ToolWindowDisabled;
|
||||
ApplicationManager.getApplication().invokeLater(() -> toolWindow.setIcon(icon));
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private final class MyDebuggerStatusChangedListener implements XDebuggerManagerListener {
|
||||
@Override
|
||||
public void processStarted(@NotNull XDebugProcess xDebugProcess) {
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
XDebugSession session = xDebugProcess.getSession();
|
||||
addNewSession(session);
|
||||
updateView(session);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processStopped(@NotNull XDebugProcess xDebugProcess) {
|
||||
XDebugSession session = xDebugProcess.getSession();
|
||||
removeSession(session);
|
||||
ApplicationManager.getApplication().invokeLater(() -> updateView(session));
|
||||
}
|
||||
|
||||
private void updateView(@NotNull XDebugSession debugSession) {
|
||||
Project project = debugSession.getProject();
|
||||
if (!project.isDisposed()) {
|
||||
ToolWindow toolWindow = getToolWindow(project);
|
||||
if (toolWindow != null) {
|
||||
updateCurrentMemoryView(project, toolWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.tracking;
|
||||
|
||||
interface BackgroundTracker {
|
||||
void setBackgroundMode(boolean isBackgroundMode);
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.tracking;
|
||||
|
||||
import com.intellij.debugger.DebuggerManager;
|
||||
import com.intellij.debugger.engine.DebugProcess;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.requests.ClassPrepareRequestor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import com.sun.jdi.request.ClassPrepareRequest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class ClassPreparedListener {
|
||||
private final XDebugSession myDebugSession;
|
||||
private final Project myProject;
|
||||
|
||||
protected ClassPreparedListener(@NotNull String className,
|
||||
@NotNull XDebugSession debugSession) {
|
||||
myProject = debugSession.getProject();
|
||||
myDebugSession = debugSession;
|
||||
DebugProcessImpl debugProcess = getDebugProcess();
|
||||
ClassPrepareRequestor request = new MyClassPreparedRequest();
|
||||
ClassPrepareRequest classPrepareRequest = debugProcess.getRequestsManager()
|
||||
.createClassPrepareRequest(request, className);
|
||||
if (classPrepareRequest != null) {
|
||||
classPrepareRequest.enable();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onClassPrepared(@NotNull ReferenceType referenceType);
|
||||
|
||||
private DebugProcessImpl getDebugProcess() {
|
||||
return (DebugProcessImpl) DebuggerManager.getInstance(myProject)
|
||||
.getDebugProcess(myDebugSession.getDebugProcess().getProcessHandler());
|
||||
}
|
||||
|
||||
private final class MyClassPreparedRequest implements ClassPrepareRequestor {
|
||||
@Override
|
||||
public void processClassPrepare(DebugProcess debuggerProcess, ReferenceType referenceType) {
|
||||
getDebugProcess().getRequestsManager().deleteRequest(this);
|
||||
onClassPrepared(referenceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
+263
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.tracking;
|
||||
|
||||
import com.intellij.debugger.DebuggerManager;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import com.intellij.debugger.memory.component.CreationPositionTracker;
|
||||
import com.intellij.debugger.memory.component.InstancesTracker;
|
||||
import com.intellij.debugger.memory.event.InstancesTrackerListener;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType;
|
||||
import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebuggerManager;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpoint;
|
||||
import com.intellij.xdebugger.impl.XDebuggerManagerImpl;
|
||||
import com.intellij.xdebugger.impl.breakpoints.LineBreakpointState;
|
||||
import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl;
|
||||
import com.sun.jdi.Location;
|
||||
import com.sun.jdi.Method;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import com.sun.jdi.event.LocatableEvent;
|
||||
import com.sun.jdi.request.BreakpointRequest;
|
||||
import com.sun.jdi.request.EventRequest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class ConstructorInstancesTracker implements TrackerForNewInstances, Disposable, BackgroundTracker {
|
||||
private static final int TRACKED_INSTANCES_LIMIT = 2000;
|
||||
private final ReferenceType myReference;
|
||||
private final XDebugSession myDebugSession;
|
||||
private final CreationPositionTracker myPositionTracker;
|
||||
private final DebugProcessImpl myDebugProcess;
|
||||
private final MyConstructorBreakpoints myBreakpoint;
|
||||
|
||||
@Nullable
|
||||
private HashSet<ObjectReference> myNewObjects = null;
|
||||
|
||||
@NotNull
|
||||
private HashSet<ObjectReference> myTrackedObjects = new HashSet<>();
|
||||
|
||||
private volatile boolean myIsBackgroundMode;
|
||||
private volatile boolean myIsBackgroundTrackingEnabled;
|
||||
|
||||
public ConstructorInstancesTracker(@NotNull ReferenceType ref,
|
||||
@NotNull XDebugSession debugSession) {
|
||||
myReference = ref;
|
||||
myDebugSession = debugSession;
|
||||
myPositionTracker = CreationPositionTracker.getInstance(debugSession.getProject());
|
||||
Project project = debugSession.getProject();
|
||||
myIsBackgroundTrackingEnabled = InstancesTracker.getInstance(myDebugSession.getProject())
|
||||
.isBackgroundTrackingEnabled();
|
||||
|
||||
InstancesTracker.getInstance(myDebugSession.getProject()).addTrackerListener(new InstancesTrackerListener() {
|
||||
@Override
|
||||
public void backgroundTrackingValueChanged(boolean newState) {
|
||||
if (myIsBackgroundTrackingEnabled != newState) {
|
||||
myIsBackgroundTrackingEnabled = newState;
|
||||
myDebugProcess.getManagerThread().schedule(new DebuggerCommandImpl() {
|
||||
@Override
|
||||
protected void action() throws Exception {
|
||||
if (newState) {
|
||||
myBreakpoint.enable();
|
||||
}
|
||||
else {
|
||||
myBreakpoint.disable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
|
||||
myDebugProcess = (DebugProcessImpl)DebuggerManager.getInstance(project)
|
||||
.getDebugProcess(debugSession.getDebugProcess().getProcessHandler());
|
||||
JavaLineBreakpointType breakPointType = new JavaLineBreakpointType();
|
||||
|
||||
XBreakpoint bpn = new XLineBreakpointImpl<>(breakPointType,
|
||||
((XDebuggerManagerImpl)XDebuggerManager.getInstance(project)).getBreakpointManager(),
|
||||
new JavaLineBreakpointProperties(),
|
||||
new LineBreakpointState<>());
|
||||
|
||||
myBreakpoint = new MyConstructorBreakpoints(project, bpn);
|
||||
myBreakpoint.createRequestForPreparedClass(myDebugProcess, myReference);
|
||||
}
|
||||
|
||||
public void obsolete() {
|
||||
if (myNewObjects != null) {
|
||||
myNewObjects.forEach(ObjectReference::enableCollection);
|
||||
}
|
||||
|
||||
myNewObjects = null;
|
||||
if (!myIsBackgroundMode || myIsBackgroundTrackingEnabled) {
|
||||
myBreakpoint.enable();
|
||||
}
|
||||
myPositionTracker.releaseBySession(myDebugSession);
|
||||
}
|
||||
|
||||
public void commitTracked() {
|
||||
myNewObjects = myTrackedObjects;
|
||||
myTrackedObjects = new HashSet<>();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<ObjectReference> getNewInstances() {
|
||||
return myNewObjects == null ? Collections.EMPTY_LIST : new ArrayList<>(myNewObjects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return myNewObjects == null ? 0 : myNewObjects.size();
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
myBreakpoint.enable();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
myBreakpoint.disable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return myNewObjects != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
Disposer.dispose(myBreakpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundMode(boolean isBackgroundMode) {
|
||||
if (myIsBackgroundMode == isBackgroundMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
myIsBackgroundMode = isBackgroundMode;
|
||||
if (isBackgroundMode) {
|
||||
doEnableBackgroundMode();
|
||||
}
|
||||
else {
|
||||
doDisableBackgroundMode();
|
||||
}
|
||||
}
|
||||
|
||||
private void doDisableBackgroundMode() {
|
||||
myBreakpoint.enable();
|
||||
}
|
||||
|
||||
private void doEnableBackgroundMode() {
|
||||
if (!myIsBackgroundTrackingEnabled) {
|
||||
myBreakpoint.disable();
|
||||
}
|
||||
}
|
||||
|
||||
private final class MyConstructorBreakpoints extends LineBreakpoint<JavaLineBreakpointProperties> implements Disposable {
|
||||
private boolean myIsEnabled = false;
|
||||
private final List<BreakpointRequest> myRequests = new ArrayList<>();
|
||||
private volatile boolean myIsDeleted = false;
|
||||
|
||||
MyConstructorBreakpoints(Project project, XBreakpoint xBreakpoint) {
|
||||
super(project, xBreakpoint);
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createRequestForPreparedClass(DebugProcessImpl debugProcess, ReferenceType classType) {
|
||||
classType.methods().stream().filter(Method::isConstructor).forEach(cons -> {
|
||||
Location loc = cons.location();
|
||||
BreakpointRequest breakpointRequest = debugProcess.getRequestsManager().createBreakpointRequest(this, loc);
|
||||
myRequests.add(breakpointRequest);
|
||||
});
|
||||
|
||||
if (!myIsBackgroundMode || myIsBackgroundTrackingEnabled) {
|
||||
enable();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
myDebugProcess.getManagerThread().schedule(new DebuggerCommandImpl() {
|
||||
@Override
|
||||
protected void action() throws Exception {
|
||||
disable();
|
||||
myDebugProcess.getRequestsManager().deleteRequest(MyConstructorBreakpoints.this);
|
||||
myIsDeleted = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processLocatableEvent(SuspendContextCommandImpl action, LocatableEvent event)
|
||||
throws EventProcessingException {
|
||||
try {
|
||||
SuspendContextImpl suspendContext = action.getSuspendContext();
|
||||
if (suspendContext != null) {
|
||||
ObjectReference thisRef = getThisObject(suspendContext, event);
|
||||
if (myReference.equals(thisRef.referenceType()) && myPositionTracker != null) {
|
||||
thisRef.disableCollection();
|
||||
myTrackedObjects.add(thisRef);
|
||||
myPositionTracker.addStack(myDebugSession, thisRef, StackFrameItem.createFrames(suspendContext.getThread()));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (myTrackedObjects.size() >= TRACKED_INSTANCES_LIMIT) {
|
||||
disable();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void enable() {
|
||||
if (!myIsEnabled && !myIsDeleted) {
|
||||
myRequests.forEach(EventRequest::enable);
|
||||
myIsEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void disable() {
|
||||
if (myIsEnabled && !myIsDeleted) {
|
||||
myRequests.forEach(EventRequest::disable);
|
||||
myIsEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.tracking;
|
||||
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TrackerForNewInstances {
|
||||
@NotNull
|
||||
List<ObjectReference> getNewInstances();
|
||||
|
||||
int getCount();
|
||||
|
||||
boolean isReady();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.tracking;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public enum TrackingType {
|
||||
CREATION("Track Constructors");
|
||||
|
||||
private final String myDescription;
|
||||
|
||||
TrackingType(@SuppressWarnings("SameParameterValue") @NotNull String description) {
|
||||
myDescription = description;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String description() {
|
||||
return myDescription;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.debugger.DebuggerManager;
|
||||
import com.intellij.debugger.DebuggerManagerEx;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
|
||||
import com.intellij.debugger.memory.event.MemoryViewManagerListener;
|
||||
import com.intellij.debugger.memory.utils.KeyboardUtils;
|
||||
import com.intellij.debugger.memory.utils.LowestPriorityCommand;
|
||||
import com.intellij.debugger.memory.utils.SingleAlarmWithMutableDelay;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.ActionPopupMenu;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebugSessionListener;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import com.sun.jdi.VirtualMachine;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.debugger.memory.component.CreationPositionTracker;
|
||||
import com.intellij.debugger.memory.component.InstancesTracker;
|
||||
import com.intellij.debugger.memory.component.MemoryViewManager;
|
||||
import com.intellij.debugger.memory.component.MemoryViewManagerState;
|
||||
import com.intellij.debugger.memory.event.InstancesTrackerListener;
|
||||
import com.intellij.debugger.memory.tracking.ClassPreparedListener;
|
||||
import com.intellij.debugger.memory.tracking.ConstructorInstancesTracker;
|
||||
import com.intellij.debugger.memory.tracking.TrackerForNewInstances;
|
||||
import com.intellij.debugger.memory.tracking.TrackingType;
|
||||
import com.intellij.debugger.memory.utils.AndroidUtil;
|
||||
|
||||
import javax.swing.FocusManager;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static com.intellij.debugger.memory.ui.ClassesTable.DiffViewTableModel.CLASSNAME_COLUMN_INDEX;
|
||||
import static com.intellij.debugger.memory.ui.ClassesTable.DiffViewTableModel.DIFF_COLUMN_INDEX;
|
||||
|
||||
public class ClassesFilteredView extends BorderLayoutPanel implements Disposable {
|
||||
private static final Logger LOG = Logger.getInstance(ClassesFilteredView.class);
|
||||
private final static double DELAY_BEFORE_INSTANCES_QUERY_COEFFICIENT = 0.5;
|
||||
private final static double MAX_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(2);
|
||||
private final static int DEFAULT_BATCH_SIZE = Integer.MAX_VALUE;
|
||||
private static final String EMPTY_TABLE_CONTENT_WHEN_RUNNING = "The application is running";
|
||||
private static final String EMPTY_TABLE_CONTENT_WHEN_SUSPENDED = "Nothing to show";
|
||||
|
||||
private final Project myProject;
|
||||
private final XDebugSession myDebugSession;
|
||||
private final DebugProcessImpl myDebugProcess;
|
||||
private final SingleAlarmWithMutableDelay mySingleAlarm;
|
||||
|
||||
private final SearchTextField myFilterTextField = new FilterTextField();
|
||||
private final ClassesTable myTable;
|
||||
private final InstancesTracker myInstancesTracker;
|
||||
private final Map<ReferenceType, ConstructorInstancesTracker> myConstructorTrackedClasses = new ConcurrentHashMap<>();
|
||||
private final XDebugSessionListener myDebugSessionListener;
|
||||
|
||||
@Nullable
|
||||
private volatile SuspendContextImpl myLastSuspendContext;
|
||||
|
||||
/**
|
||||
* Indicates that the debug session had been stopped at least once.
|
||||
* <p>
|
||||
* State: false to true
|
||||
*/
|
||||
private volatile boolean myIsTrackersActivated = false;
|
||||
|
||||
/**
|
||||
* Indicates that view is visible in tool window
|
||||
*/
|
||||
private boolean myIsActive;
|
||||
|
||||
public ClassesFilteredView(@NotNull XDebugSession debugSession) {
|
||||
super();
|
||||
|
||||
myProject = debugSession.getProject();
|
||||
myDebugSession = debugSession;
|
||||
myDebugProcess = (DebugProcessImpl) DebuggerManager.getInstance(myProject)
|
||||
.getDebugProcess(myDebugSession.getDebugProcess().getProcessHandler());
|
||||
|
||||
if (myDebugProcess == null) {
|
||||
throw new NullPointerException("Failed to receive a java debug process");
|
||||
}
|
||||
|
||||
myInstancesTracker = InstancesTracker.getInstance(myProject);
|
||||
InstancesTrackerListener instancesTrackerListener = new InstancesTrackerListener() {
|
||||
@Override
|
||||
public void classChanged(@NotNull String name, @NotNull TrackingType type) {
|
||||
ReferenceType ref = myTable.getClassByName(name);
|
||||
if (ref != null) {
|
||||
myDebugProcess.getManagerThread()
|
||||
.schedule(new LowestPriorityCommand(getSuspendContext()) {
|
||||
@Override
|
||||
public void contextAction(@NotNull SuspendContextImpl suspendContext) throws Exception {
|
||||
trackClass(ref, type, myIsTrackersActivated);
|
||||
}
|
||||
});
|
||||
}
|
||||
myTable.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classRemoved(@NotNull String name) {
|
||||
ReferenceType ref = myTable.getClassByName(name);
|
||||
if (ref != null && myConstructorTrackedClasses.containsKey(ref)) {
|
||||
ConstructorInstancesTracker removed = myConstructorTrackedClasses.remove(ref);
|
||||
Disposer.dispose(removed);
|
||||
myTable.getRowSorter().allRowsChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
myDebugProcess.getManagerThread().schedule(new DebuggerCommandImpl() {
|
||||
@Override
|
||||
public Priority getPriority() {
|
||||
return Priority.LOWEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void action() throws Exception {
|
||||
for (Map.Entry<String, TrackingType> entry : myInstancesTracker.getTrackedClasses().entrySet()) {
|
||||
TrackingType type = entry.getValue();
|
||||
String className = entry.getKey();
|
||||
List<ReferenceType> classes = myDebugProcess.getVirtualMachineProxy().classesByName(className);
|
||||
if (classes.isEmpty()) {
|
||||
new ClassPreparedListener(className, myDebugSession) {
|
||||
@Override
|
||||
public void onClassPrepared(@NotNull ReferenceType referenceType) {
|
||||
trackClass(referenceType, type, myIsTrackersActivated);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
for (ReferenceType ref : classes) {
|
||||
trackClass(ref, type, myIsTrackersActivated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myInstancesTracker.addTrackerListener(instancesTrackerListener, ClassesFilteredView.this);
|
||||
}
|
||||
});
|
||||
|
||||
MemoryViewManagerState memoryViewManagerState = MemoryViewManager.getInstance().getState();
|
||||
|
||||
myTable = new ClassesTable(myDebugSession, memoryViewManagerState.isShowWithDiffOnly,
|
||||
memoryViewManagerState.isShowWithInstancesOnly, memoryViewManagerState.isShowTrackedOnly, this);
|
||||
myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_RUNNING);
|
||||
Disposer.register(this, myTable);
|
||||
|
||||
myTable.addMouseMotionListener(new MyMouseMotionListener());
|
||||
myTable.addMouseListener(new MyOpenNewInstancesListener());
|
||||
new MyDoubleClickListener().installOn(myTable);
|
||||
|
||||
myTable.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
int keyCode = e.getKeyCode();
|
||||
if (KeyboardUtils.isEnterKey(keyCode)) {
|
||||
handleClassSelection(myTable.getSelectedClass());
|
||||
} else if (KeyboardUtils.isCharacter(keyCode) || KeyboardUtils.isBackSpace(keyCode)) {
|
||||
String text = myFilterTextField.getText();
|
||||
String newText = KeyboardUtils.isBackSpace(keyCode)
|
||||
? text.substring(0, text.length() - 1)
|
||||
: text + e.getKeyChar();
|
||||
myFilterTextField.setText(newText);
|
||||
FocusManager.getCurrentManager().focusNextComponent(myFilterTextField);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
myFilterTextField.addKeyboardListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
dispatch(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
dispatch(e);
|
||||
}
|
||||
|
||||
private void dispatch(KeyEvent e) {
|
||||
if (KeyboardUtils.isUpDownKey(e.getKeyCode()) || KeyboardUtils.isEnterKey(e.getKeyCode())) {
|
||||
myTable.dispatchEvent(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
myFilterTextField.addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
myTable.setFilterPattern(myFilterTextField.getText());
|
||||
}
|
||||
});
|
||||
|
||||
final MemoryViewManagerListener memoryViewManagerListener = state -> {
|
||||
myTable.setFilteringByDiffNonZero(state.isShowWithDiffOnly);
|
||||
myTable.setFilteringByInstanceExists(state.isShowWithInstancesOnly);
|
||||
myTable.setFilteringByTrackingState(state.isShowTrackedOnly);
|
||||
};
|
||||
|
||||
MemoryViewManager.getInstance().addMemoryViewManagerListener(memoryViewManagerListener, this);
|
||||
|
||||
myDebugSessionListener = new XDebugSessionListener() {
|
||||
@Override
|
||||
public void sessionResumed() {
|
||||
myConstructorTrackedClasses.values().forEach(ConstructorInstancesTracker::obsolete);
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_RUNNING);
|
||||
myTable.hideContent();
|
||||
});
|
||||
mySingleAlarm.cancelAllRequests();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionStopped() {
|
||||
debugSession.removeSessionListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionPaused() {
|
||||
ApplicationManager.getApplication().invokeLater(() -> myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_SUSPENDED));
|
||||
updateClassesAndCounts();
|
||||
}
|
||||
};
|
||||
|
||||
mySingleAlarm = new SingleAlarmWithMutableDelay(() -> {
|
||||
myLastSuspendContext = getSuspendContext();
|
||||
if (myLastSuspendContext != null) {
|
||||
ApplicationManager.getApplication().invokeLater(() -> myTable.setBusy(true));
|
||||
myDebugProcess.getManagerThread()
|
||||
.schedule(new MyUpdateClassesCommand(myLastSuspendContext));
|
||||
}
|
||||
}, this);
|
||||
|
||||
myTable.addMouseListener(new PopupHandler() {
|
||||
@Override
|
||||
public void invokePopup(Component comp, int x, int y) {
|
||||
ActionPopupMenu menu = createContextMenu();
|
||||
if (menu != null) {
|
||||
menu.getComponent().show(comp, x, y);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JScrollPane scroll = ScrollPaneFactory.createScrollPane(myTable, SideBorder.TOP);
|
||||
addToTop(myFilterTextField);
|
||||
addToCenter(scroll);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
TrackerForNewInstances getStrategy(@NotNull ReferenceType ref) {
|
||||
return myConstructorTrackedClasses.getOrDefault(ref, null);
|
||||
}
|
||||
|
||||
private void trackClass(@NotNull ReferenceType ref,
|
||||
@NotNull TrackingType type,
|
||||
boolean isTrackerEnabled) {
|
||||
LOG.assertTrue(DebuggerManager.getInstance(myProject).isDebuggerManagerThread());
|
||||
if (type == TrackingType.CREATION) {
|
||||
ConstructorInstancesTracker old = myConstructorTrackedClasses.getOrDefault(ref, null);
|
||||
if (old != null) {
|
||||
Disposer.dispose(old);
|
||||
}
|
||||
|
||||
ConstructorInstancesTracker tracker = new ConstructorInstancesTracker(ref, myDebugSession);
|
||||
tracker.setBackgroundMode(!myIsActive);
|
||||
if (isTrackerEnabled) {
|
||||
tracker.enable();
|
||||
} else {
|
||||
tracker.disable();
|
||||
}
|
||||
|
||||
Disposer.register(this, tracker);
|
||||
myConstructorTrackedClasses.put(ref, tracker);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleClassSelection(@Nullable ReferenceType ref) {
|
||||
if (ref != null && myDebugSession.isSuspended()) {
|
||||
new InstancesWindow(myDebugSession, ref::instances, ref.name()).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void commitAllTrackers() {
|
||||
myConstructorTrackedClasses.values().forEach(ConstructorInstancesTracker::commitTracked);
|
||||
}
|
||||
|
||||
private SuspendContextImpl getSuspendContext() {
|
||||
return DebuggerManagerEx.getInstanceEx(myProject).getContext().getSuspendContext();
|
||||
}
|
||||
|
||||
private void updateClassesAndCounts() {
|
||||
if (myDebugProcess.isAttached()) {
|
||||
mySingleAlarm.cancelAndRequest();
|
||||
}
|
||||
}
|
||||
|
||||
private static ActionPopupMenu createContextMenu() {
|
||||
ActionGroup group = (ActionGroup) ActionManager.getInstance().getAction("MemoryView.ClassesPopupActionGroup");
|
||||
return ActionManager.getInstance().createActionPopupMenu("MemoryView.ClassesPopupActionGroup", group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
if (myIsActive == active) {
|
||||
return;
|
||||
}
|
||||
|
||||
myIsActive = active;
|
||||
myDebugProcess.getManagerThread().schedule(new DebuggerCommandImpl() {
|
||||
@Override
|
||||
protected void action() throws Exception {
|
||||
if (active) {
|
||||
doActivate();
|
||||
} else {
|
||||
doPause();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doActivate() {
|
||||
myDebugSession.addSessionListener(myDebugSessionListener, this);
|
||||
myConstructorTrackedClasses.values().forEach(x -> x.setBackgroundMode(false));
|
||||
final SuspendContextImpl lastContext = myLastSuspendContext;
|
||||
if (lastContext == null || !lastContext.equals(getSuspendContext())) {
|
||||
updateClassesAndCounts();
|
||||
}
|
||||
}
|
||||
|
||||
private void doPause() {
|
||||
myDebugSession.removeSessionListener(myDebugSessionListener);
|
||||
myConstructorTrackedClasses.values().forEach(x -> x.setBackgroundMode(true));
|
||||
}
|
||||
|
||||
private final class MyUpdateClassesCommand extends LowestPriorityCommand {
|
||||
|
||||
MyUpdateClassesCommand(@Nullable SuspendContextImpl suspendContext) {
|
||||
super(suspendContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextAction(@NotNull SuspendContextImpl suspendContext) throws Exception {
|
||||
if (!myIsTrackersActivated) {
|
||||
myConstructorTrackedClasses.values().forEach(ConstructorInstancesTracker::enable);
|
||||
myIsTrackersActivated = true;
|
||||
} else {
|
||||
commitAllTrackers();
|
||||
}
|
||||
final List<ReferenceType> classes = myDebugProcess.getVirtualMachineProxy().allClasses();
|
||||
|
||||
if (classes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
VirtualMachine vm = classes.get(0).virtualMachine();
|
||||
int batchSize = AndroidUtil.isAndroidVM(vm)
|
||||
? AndroidUtil.ANDROID_COUNT_BY_CLASSES_BATCH_SIZE
|
||||
: DEFAULT_BATCH_SIZE;
|
||||
|
||||
List<long[]> chunks = new SmartList<>();
|
||||
int size = classes.size();
|
||||
for (int begin = 0, end = Math.min(batchSize, size);
|
||||
begin != size && isContextValid();
|
||||
begin = end, end = Math.min(end + batchSize, size)) {
|
||||
List<ReferenceType> batch = classes.subList(begin, end);
|
||||
|
||||
long start = System.nanoTime();
|
||||
long[] counts = vm.instanceCounts(batch);
|
||||
long delay = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
|
||||
|
||||
chunks.add(counts);
|
||||
|
||||
int waitTime = (int) Math.min(DELAY_BEFORE_INSTANCES_QUERY_COEFFICIENT * delay, MAX_DELAY_MILLIS);
|
||||
mySingleAlarm.setDelay(waitTime);
|
||||
LOG.info(String.format("Instances query time = %d ms. Count = %d", delay, batch.size()));
|
||||
}
|
||||
|
||||
if (isContextValid()) {
|
||||
final long[] counts = chunks.size() == 1 ? chunks.get(0) : IntStream.range(0, chunks.size()).boxed()
|
||||
.flatMapToLong(integer -> Arrays.stream(chunks.get(integer)))
|
||||
.toArray();
|
||||
ApplicationManager.getApplication().invokeLater(() -> myTable.setClassesAndUpdateCounts(classes, counts));
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(() -> myTable.setBusy(false));
|
||||
}
|
||||
|
||||
private boolean isContextValid() {
|
||||
return ClassesFilteredView.this.getSuspendContext() == getSuspendContext();
|
||||
}
|
||||
}
|
||||
|
||||
private static class FilterTextField extends SearchTextField {
|
||||
FilterTextField() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showPopup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasIconsOutsideOfTextField() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyOpenNewInstancesListener extends MouseAdapter {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() != 1 || e.getButton() != MouseEvent.BUTTON1 || !isShowNewInstancesEvent(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final CreationPositionTracker tracker = CreationPositionTracker.getInstance(myDebugSession.getProject());
|
||||
ReferenceType ref = myTable.getSelectedClass();
|
||||
TrackerForNewInstances strategy = ref == null ? null : getStrategy(ref);
|
||||
if (strategy != null && tracker != null) {
|
||||
List<ObjectReference> newInstances = strategy.getNewInstances();
|
||||
tracker.pinStacks(myDebugSession, ref);
|
||||
InstancesWindow instancesWindow = new InstancesWindow(myDebugSession, limit -> newInstances, ref.name());
|
||||
Disposer.register(instancesWindow.getDisposable(), () -> tracker.unpinStacks(myDebugSession, ref));
|
||||
instancesWindow.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyDoubleClickListener extends DoubleClickListener {
|
||||
@Override
|
||||
protected boolean onDoubleClick(MouseEvent event) {
|
||||
if (!isShowNewInstancesEvent(event)) {
|
||||
handleClassSelection(myTable.getSelectedClass());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyMouseMotionListener implements MouseMotionListener {
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
if (isShowNewInstancesEvent(e)) {
|
||||
myTable.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
} else {
|
||||
myTable.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isShowNewInstancesEvent(@NotNull MouseEvent e) {
|
||||
final int col = myTable.columnAtPoint(e.getPoint());
|
||||
final int row = myTable.rowAtPoint(e.getPoint());
|
||||
if (col == -1 || row == -1 || myTable.convertColumnIndexToModel(col) != DIFF_COLUMN_INDEX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int modelRow = myTable.convertRowIndexToModel(row);
|
||||
|
||||
final ReferenceType ref = (ReferenceType) myTable.getModel().getValueAt(modelRow, CLASSNAME_COLUMN_INDEX);
|
||||
final ConstructorInstancesTracker tracker = myConstructorTrackedClasses.getOrDefault(ref, null);
|
||||
|
||||
return tracker != null && tracker.isReady() && tracker.getCount() > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.debugger.memory.component.InstancesTracker;
|
||||
import com.intellij.debugger.memory.utils.AbstractTableColumnDescriptor;
|
||||
import com.intellij.debugger.memory.utils.AbstractTableModelWithColumns;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import com.intellij.openapi.actionSystem.DataProvider;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.codeStyle.MinusculeMatcher;
|
||||
import com.intellij.psi.codeStyle.NameUtil;
|
||||
import com.intellij.ui.ColoredTableCellRenderer;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.ui.speedSearch.SpeedSearchUtil;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.containers.FList;
|
||||
import com.intellij.util.ui.JBDimension;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.debugger.memory.tracking.TrackerForNewInstances;
|
||||
import com.intellij.debugger.memory.tracking.TrackingType;
|
||||
import com.intellij.debugger.memory.utils.InstancesProvider;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.table.TableColumn;
|
||||
import javax.swing.table.TableRowSorter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ClassesTable extends JBTable implements DataProvider, Disposable {
|
||||
public static final DataKey<ReferenceType> SELECTED_CLASS_KEY = DataKey.create("ClassesTable.SelectedClass");
|
||||
public static final DataKey<XDebugSession> DEBUG_SESSION_KEY = DataKey.create("ClassesTable.DebugSession");
|
||||
public static final DataKey<InstancesProvider> NEW_INSTANCES_PROVIDER_KEY =
|
||||
DataKey.create("ClassesTable.NewInstances");
|
||||
public static final DataKey<ReferenceCountProvider> REF_COUNT_PROVIDER_KEY =
|
||||
DataKey.create("ClassesTable.ReferenceCountProvider");
|
||||
|
||||
private static final Border EMPTY_BORDER = BorderFactory.createEmptyBorder();
|
||||
|
||||
private static final int CLASSES_COLUMN_PREFERRED_WIDTH = 250;
|
||||
private static final int COUNT_COLUMN_MIN_WIDTH = 80;
|
||||
private static final int DIFF_COLUMN_MIN_WIDTH = 80;
|
||||
|
||||
private final DiffViewTableModel myModel = new DiffViewTableModel();
|
||||
private final UnknownDiffValue myUnknownValue = new UnknownDiffValue();
|
||||
private final XDebugSession myDebugSession;
|
||||
private final Map<ReferenceType, DiffValue> myCounts = new ConcurrentHashMap<>();
|
||||
private final InstancesTracker myInstancesTracker;
|
||||
private final ClassesFilteredView myParent;
|
||||
private final ReferenceCountProvider myCountProvider;
|
||||
|
||||
private boolean myOnlyWithDiff;
|
||||
private boolean myOnlyTracked;
|
||||
private boolean myOnlyWithInstances;
|
||||
private MinusculeMatcher myMatcher = NameUtil.buildMatcher("*").build();
|
||||
private String myFilteringPattern = "";
|
||||
|
||||
private volatile List<ReferenceType> myItems = Collections.unmodifiableList(new ArrayList<>());
|
||||
|
||||
ClassesTable(@NotNull XDebugSession session, boolean onlyWithDiff, boolean onlyWithInstances,
|
||||
boolean onlyTracked, @NotNull ClassesFilteredView parent) {
|
||||
setModel(myModel);
|
||||
|
||||
myDebugSession = session;
|
||||
myOnlyWithDiff = onlyWithDiff;
|
||||
myOnlyWithInstances = onlyWithInstances;
|
||||
myOnlyTracked = onlyTracked;
|
||||
myInstancesTracker = InstancesTracker.getInstance(myDebugSession.getProject());
|
||||
myParent = parent;
|
||||
|
||||
TableColumn classesColumn = getColumnModel().getColumn(DiffViewTableModel.CLASSNAME_COLUMN_INDEX);
|
||||
TableColumn countColumn = getColumnModel().getColumn(DiffViewTableModel.COUNT_COLUMN_INDEX);
|
||||
TableColumn diffColumn = getColumnModel().getColumn(DiffViewTableModel.DIFF_COLUMN_INDEX);
|
||||
|
||||
setAutoResizeMode(AUTO_RESIZE_NEXT_COLUMN);
|
||||
classesColumn.setPreferredWidth(JBUI.scale(CLASSES_COLUMN_PREFERRED_WIDTH));
|
||||
|
||||
countColumn.setMinWidth(JBUI.scale(COUNT_COLUMN_MIN_WIDTH));
|
||||
|
||||
diffColumn.setMinWidth(JBUI.scale(DIFF_COLUMN_MIN_WIDTH));
|
||||
|
||||
setShowGrid(false);
|
||||
setIntercellSpacing(new JBDimension(0, 0));
|
||||
|
||||
setDefaultRenderer(ReferenceType.class, new MyClassColumnRenderer());
|
||||
setDefaultRenderer(Long.class, new MyCountColumnRenderer());
|
||||
setDefaultRenderer(DiffValue.class, new MyDiffColumnRenderer());
|
||||
|
||||
TableRowSorter<DiffViewTableModel> sorter = new TableRowSorter<>(myModel);
|
||||
sorter.setRowFilter(new RowFilter<DiffViewTableModel, Integer>() {
|
||||
@Override
|
||||
public boolean include(Entry<? extends DiffViewTableModel, ? extends Integer> entry) {
|
||||
int ix = entry.getIdentifier();
|
||||
ReferenceType ref = myItems.get(ix);
|
||||
DiffValue diff = myCounts.getOrDefault(ref, myUnknownValue);
|
||||
|
||||
boolean isFilteringOptionsRefused = myOnlyWithDiff && diff.diff() == 0
|
||||
|| myOnlyWithInstances && !diff.hasInstance()
|
||||
|| myOnlyTracked && myParent.getStrategy(ref) == null;
|
||||
return !(isFilteringOptionsRefused) && myMatcher.matches(ref.name());
|
||||
}
|
||||
});
|
||||
|
||||
List<RowSorter.SortKey> myDefaultSortingKeys = Arrays.asList(
|
||||
new RowSorter.SortKey(DiffViewTableModel.DIFF_COLUMN_INDEX, SortOrder.DESCENDING),
|
||||
new RowSorter.SortKey(DiffViewTableModel.COUNT_COLUMN_INDEX, SortOrder.DESCENDING),
|
||||
new RowSorter.SortKey(DiffViewTableModel.CLASSNAME_COLUMN_INDEX, SortOrder.ASCENDING)
|
||||
);
|
||||
sorter.setSortKeys(myDefaultSortingKeys);
|
||||
setRowSorter(sorter);
|
||||
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
myCountProvider = new ReferenceCountProvider() {
|
||||
@Override
|
||||
public int getTotalCount(@NotNull ReferenceType ref) {
|
||||
return (int)myCounts.get(ref).myCurrentCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDiffCount(@NotNull ReferenceType ref) {
|
||||
return (int)myCounts.get(ref).diff();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNewInstancesCount(@NotNull ReferenceType ref) {
|
||||
TrackerForNewInstances strategy = myParent.getStrategy(ref);
|
||||
return strategy == null || !strategy.isReady() ? -1 : strategy.getCount();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public interface ReferenceCountProvider {
|
||||
int getTotalCount(@NotNull ReferenceType ref);
|
||||
|
||||
int getDiffCount(@NotNull ReferenceType ref);
|
||||
|
||||
int getNewInstancesCount(@NotNull ReferenceType ref);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
ReferenceType getSelectedClass() {
|
||||
int selectedRow = getSelectedRow();
|
||||
if (selectedRow != -1) {
|
||||
int ix = convertRowIndexToModel(selectedRow);
|
||||
return myItems.get(ix);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
ReferenceType getClassByName(@NotNull String name) {
|
||||
for (ReferenceType ref : myItems) {
|
||||
if (name.equals(ref.name())) {
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void setBusy(boolean value) {
|
||||
setPaintBusy(value);
|
||||
}
|
||||
|
||||
void setFilterPattern(String pattern) {
|
||||
if (!myFilteringPattern.equals(pattern)) {
|
||||
myFilteringPattern = pattern;
|
||||
myMatcher = NameUtil.buildMatcher("*" + pattern).build();
|
||||
getRowSorter().allRowsChanged();
|
||||
if (getSelectedClass() == null && getRowCount() > 0) {
|
||||
getSelectionModel().setSelectionInterval(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setFilteringByInstanceExists(boolean value) {
|
||||
if (value != myOnlyWithInstances) {
|
||||
myOnlyWithInstances = value;
|
||||
getRowSorter().allRowsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void setFilteringByDiffNonZero(boolean value) {
|
||||
if (myOnlyWithDiff != value) {
|
||||
myOnlyWithDiff = value;
|
||||
getRowSorter().allRowsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void setFilteringByTrackingState(boolean value) {
|
||||
if (myOnlyTracked != value) {
|
||||
myOnlyTracked = value;
|
||||
getRowSorter().allRowsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void setClassesAndUpdateCounts(@NotNull List<ReferenceType> classes, @NotNull long[] counts) {
|
||||
assert classes.size() == counts.length;
|
||||
ReferenceType selectedClass = myModel.getSelectedClassBeforeHided();
|
||||
int newSelectedIndex = classes.indexOf(selectedClass);
|
||||
boolean isInitialized = !myItems.isEmpty();
|
||||
myItems = Collections.unmodifiableList(new ArrayList<>(classes));
|
||||
|
||||
for (int i = 0, size = classes.size(); i < size; i++) {
|
||||
ReferenceType ref = classes.get(i);
|
||||
DiffValue oldValue = isInitialized && !myCounts.containsKey(ref)
|
||||
? new DiffValue(0, 0)
|
||||
: myCounts.getOrDefault(ref, myUnknownValue);
|
||||
myCounts.put(ref, oldValue.update(counts[i]));
|
||||
}
|
||||
|
||||
showContent();
|
||||
|
||||
if (newSelectedIndex != -1 && !myModel.isHided()) {
|
||||
int ix = convertRowIndexToView(newSelectedIndex);
|
||||
changeSelection(ix,
|
||||
DiffViewTableModel.CLASSNAME_COLUMN_INDEX, false, false);
|
||||
}
|
||||
|
||||
getRowSorter().allRowsChanged();
|
||||
}
|
||||
|
||||
void hideContent() {
|
||||
myModel.hide();
|
||||
}
|
||||
|
||||
private void showContent() {
|
||||
myModel.show();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getData(@NonNls String dataId) {
|
||||
if (SELECTED_CLASS_KEY.is(dataId)) {
|
||||
return getSelectedClass();
|
||||
}
|
||||
if (DEBUG_SESSION_KEY.is(dataId)) {
|
||||
return myDebugSession;
|
||||
}
|
||||
if (NEW_INSTANCES_PROVIDER_KEY.is(dataId)) {
|
||||
ReferenceType selectedClass = getSelectedClass();
|
||||
if (selectedClass != null) {
|
||||
TrackerForNewInstances strategy = myParent.getStrategy(selectedClass);
|
||||
if (strategy != null && strategy.isReady()) {
|
||||
List<ObjectReference> newInstances = strategy.getNewInstances();
|
||||
return (InstancesProvider)limit -> newInstances;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (REF_COUNT_PROVIDER_KEY.is(dataId)) {
|
||||
return myCountProvider;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TrackingType getTrackingType(int row) {
|
||||
ReferenceType ref = (ReferenceType)getValueAt(row, convertColumnIndexToView(DiffViewTableModel.CLASSNAME_COLUMN_INDEX));
|
||||
return myInstancesTracker.getTrackingType(ref.name());
|
||||
}
|
||||
|
||||
class DiffViewTableModel extends AbstractTableModelWithColumns {
|
||||
final static int CLASSNAME_COLUMN_INDEX = 0;
|
||||
final static int COUNT_COLUMN_INDEX = 1;
|
||||
final static int DIFF_COLUMN_INDEX = 2;
|
||||
|
||||
// Workaround: save selection after content of classes table has been hided
|
||||
private ReferenceType mySelectedClassWhenHided = null;
|
||||
private boolean myIsWithContent = false;
|
||||
|
||||
DiffViewTableModel() {
|
||||
super(new AbstractTableColumnDescriptor[]{
|
||||
new AbstractTableColumnDescriptor("Class", ReferenceType.class) {
|
||||
@Override
|
||||
public Object getValue(int ix) {
|
||||
return myItems.get(ix);
|
||||
}
|
||||
},
|
||||
new AbstractTableColumnDescriptor("Count", Long.class) {
|
||||
@Override
|
||||
public Object getValue(int ix) {
|
||||
return myCounts.getOrDefault(myItems.get(ix), myUnknownValue).myCurrentCount;
|
||||
}
|
||||
},
|
||||
new AbstractTableColumnDescriptor("Diff", DiffValue.class) {
|
||||
@Override
|
||||
public Object getValue(int ix) {
|
||||
return myCounts.getOrDefault(myItems.get(ix), myUnknownValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ReferenceType getSelectedClassBeforeHided() {
|
||||
return mySelectedClassWhenHided;
|
||||
}
|
||||
|
||||
void hide() {
|
||||
if (myIsWithContent) {
|
||||
mySelectedClassWhenHided = getSelectedClass();
|
||||
myIsWithContent = false;
|
||||
clearSelection();
|
||||
fireTableDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void show() {
|
||||
if (!myIsWithContent) {
|
||||
myIsWithContent = true;
|
||||
getRowSorter().allRowsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
boolean isHided() {
|
||||
return !myIsWithContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return myIsWithContent ? myItems.size() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* State transmissions for DiffValue and UnknownDiffValue
|
||||
* unknown -> diff
|
||||
* diff -> diff
|
||||
* <p>
|
||||
* State descriptions:
|
||||
* Unknown - instances count never executed
|
||||
* Diff - actual value
|
||||
*/
|
||||
private static class UnknownDiffValue extends DiffValue {
|
||||
UnknownDiffValue() {
|
||||
super(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
DiffValue update(long count) {
|
||||
return new DiffValue(count);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DiffValue implements Comparable<DiffValue> {
|
||||
private long myOldCount;
|
||||
|
||||
private long myCurrentCount;
|
||||
|
||||
DiffValue(long count) {
|
||||
this(count, count);
|
||||
}
|
||||
|
||||
DiffValue(long old, long current) {
|
||||
myCurrentCount = current;
|
||||
myOldCount = old;
|
||||
}
|
||||
|
||||
DiffValue update(long count) {
|
||||
myOldCount = myCurrentCount;
|
||||
myCurrentCount = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean hasInstance() {
|
||||
return myCurrentCount > 0;
|
||||
}
|
||||
|
||||
long diff() {
|
||||
return myCurrentCount - myOldCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull DiffValue o) {
|
||||
return Long.compare(diff(), o.diff());
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class MyTableCellRenderer extends ColoredTableCellRenderer {
|
||||
@Override
|
||||
protected void customizeCellRenderer(JTable table, @Nullable Object value, boolean isSelected,
|
||||
boolean hasFocus, int row, int column) {
|
||||
column = convertColumnIndexToModel(column);
|
||||
TrackingType trackingType = getTrackingType(row);
|
||||
|
||||
if (hasFocus) {
|
||||
setBorder(EMPTY_BORDER);
|
||||
}
|
||||
|
||||
if (trackingType != null && column == DiffViewTableModel.DIFF_COLUMN_INDEX) {
|
||||
setIcon(AllIcons.Debugger.MemoryView.ClassTracked);
|
||||
setTransparentIconBackground(true);
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
addText(value, isSelected, row);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void addText(@NotNull Object value, boolean isSelected, int row);
|
||||
}
|
||||
|
||||
private class MyClassColumnRenderer extends MyTableCellRenderer {
|
||||
@Override
|
||||
protected void addText(@NotNull Object value, boolean isSelected,
|
||||
int row) {
|
||||
String presentation = ((ReferenceType)value).name();
|
||||
append(" ");
|
||||
if (isSelected) {
|
||||
FList<TextRange> textRanges = myMatcher.matchingFragments(presentation);
|
||||
if (textRanges != null) {
|
||||
SimpleTextAttributes attributes = new SimpleTextAttributes(getBackground(), getForeground(), null,
|
||||
SimpleTextAttributes.STYLE_SEARCH_MATCH);
|
||||
SpeedSearchUtil.appendColoredFragments(this, presentation, textRanges,
|
||||
SimpleTextAttributes.REGULAR_ATTRIBUTES, attributes);
|
||||
}
|
||||
}
|
||||
else {
|
||||
append(String.format("%s", presentation), SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyCountColumnRenderer extends MyTableCellRenderer {
|
||||
@Override
|
||||
protected void addText(@NotNull Object value, boolean isSelected,
|
||||
int row) {
|
||||
setTextAlign(SwingConstants.RIGHT);
|
||||
append(value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private class MyDiffColumnRenderer extends MyTableCellRenderer {
|
||||
private final SimpleTextAttributes myClickableCellAttributes =
|
||||
new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, JBColor.BLUE);
|
||||
|
||||
@Override
|
||||
protected void addText(@NotNull Object value, boolean isSelected,
|
||||
int row) {
|
||||
setTextAlign(SwingConstants.RIGHT);
|
||||
|
||||
ReferenceType ref = myItems.get(convertRowIndexToModel(row));
|
||||
|
||||
long diff = myCountProvider.getDiffCount(ref);
|
||||
String text = String.format("%s%d", diff > 0 ? "+" : "", diff);
|
||||
|
||||
int newInstancesCount = myCountProvider.getNewInstancesCount(ref);
|
||||
if (newInstancesCount >= 0) {
|
||||
if (newInstancesCount == diff) {
|
||||
append(text, diff == 0 ? SimpleTextAttributes.REGULAR_ATTRIBUTES : myClickableCellAttributes);
|
||||
}
|
||||
else {
|
||||
append(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
if (newInstancesCount != 0) {
|
||||
append(String.format(" (%d)", newInstancesCount), myClickableCellAttributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
append(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.debugger.engine.DebuggerUtils;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CustomShortcutSet;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.PopupStep;
|
||||
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.ui.ColoredListCellRenderer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.ui.popup.list.ListPopupImpl;
|
||||
import com.intellij.xdebugger.XExpression;
|
||||
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
|
||||
import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
|
||||
import com.intellij.xdebugger.impl.ui.XDebuggerExpressionEditor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.List;
|
||||
|
||||
class ExpressionEditorWithHistory extends XDebuggerExpressionEditor {
|
||||
private static final String HISTORY_ID_PREFIX = "filtering";
|
||||
|
||||
ExpressionEditorWithHistory(final @NotNull Project project,
|
||||
final @NotNull String className,
|
||||
final @NotNull XDebuggerEditorsProvider debuggerEditorsProvider,
|
||||
final @Nullable Disposable parentDisposable) {
|
||||
super(project, debuggerEditorsProvider, HISTORY_ID_PREFIX + className, null,
|
||||
XExpressionImpl.EMPTY_EXPRESSION, false, true, true);
|
||||
|
||||
new AnAction("InstancesWindow.ShowHistory") {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
showHistory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(LookupManager.getActiveLookup(getEditor()) == null);
|
||||
}
|
||||
}.registerCustomShortcutSet(CustomShortcutSet.fromString("DOWN"), getComponent(), parentDisposable);
|
||||
|
||||
new SwingWorker<Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
final PsiClass psiClass = DebuggerUtils.findClass(className,
|
||||
project, GlobalSearchScope.allScope(project));
|
||||
ApplicationManager.getApplication().invokeLater(() -> setContext(psiClass));
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private void showHistory() {
|
||||
List<XExpression> expressions = getRecentExpressions();
|
||||
if (!expressions.isEmpty()) {
|
||||
ListPopupImpl historyPopup = new ListPopupImpl(new BaseListPopupStep<XExpression>(null, expressions) {
|
||||
@Override
|
||||
public PopupStep onChosen(XExpression selectedValue, boolean finalChoice) {
|
||||
setExpression(selectedValue);
|
||||
requestFocusInEditor();
|
||||
return FINAL_CHOICE;
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
protected ListCellRenderer getListElementRenderer() {
|
||||
return new ColoredListCellRenderer<XExpression>() {
|
||||
@Override
|
||||
protected void customizeCellRenderer(@NotNull JList list, XExpression value, int index,
|
||||
boolean selected, boolean hasFocus) {
|
||||
append(value.getExpression(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
historyPopup.getList().setFont(EditorUtil.getEditorFont());
|
||||
historyPopup.showUnderneathOf(getEditorComponent());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.debugger.memory.filtering.FilteringResult;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ui.JBProgressBar;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
class FilteringProgressView extends BorderLayoutPanel {
|
||||
private final static String LIMIT_REACHED_LABEL = "Limit has been reached";
|
||||
private final static String INTERRUPTED_LABEL = "Filtering has been interrupted";
|
||||
|
||||
private final JBProgressBar myProgressBar = new JBProgressBar();
|
||||
private final BorderLayoutPanel myProgressPanel = new BorderLayoutPanel();
|
||||
private final JBLabel myStopButton = new JBLabel(UIUtil.isUnderDarcula()
|
||||
? AllIcons.Actions.Clean : AllIcons.Actions.CleanLight);
|
||||
private final JBLabel myProgressText = new JBLabel();
|
||||
|
||||
private int myProceedCount = 0;
|
||||
private int myErrorCount = 0;
|
||||
private int myMatchedCount = 0;
|
||||
|
||||
private boolean myIsInProcess = false;
|
||||
|
||||
@Nullable
|
||||
private FilteringResult myCompletionReason = null;
|
||||
|
||||
FilteringProgressView() {
|
||||
myStopButton.setOpaque(true);
|
||||
myProgressPanel.addToCenter(myProgressBar);
|
||||
myProgressPanel.addToRight(myStopButton);
|
||||
addToTop(myProgressText);
|
||||
addToCenter(myProgressPanel);
|
||||
}
|
||||
|
||||
void addStopActionListener(@NotNull Runnable listener) {
|
||||
myStopButton.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
listener.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void updateProgress(int proceedCount, int matchedCount, int errorCount) {
|
||||
if (myIsInProcess) {
|
||||
myProceedCount = proceedCount;
|
||||
myMatchedCount = matchedCount;
|
||||
myErrorCount = errorCount;
|
||||
myProgressBar.setValue(myProceedCount);
|
||||
myProgressText.setText(getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
void start(int totalCount) {
|
||||
reset();
|
||||
myIsInProcess = true;
|
||||
myProgressBar.setMinimum(0);
|
||||
myProgressBar.setMaximum(totalCount);
|
||||
myProgressBar.setValue(0);
|
||||
myProgressText.setText(getDescription());
|
||||
setProgressBarVisible(true);
|
||||
}
|
||||
|
||||
void complete(@NotNull FilteringResult reason) {
|
||||
if (!myIsInProcess) {
|
||||
throw new IllegalStateException("First you need to start progress");
|
||||
}
|
||||
|
||||
myIsInProcess = false;
|
||||
myCompletionReason = reason;
|
||||
myProgressText.setText(getDescription());
|
||||
setProgressBarVisible(false);
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
myIsInProcess = false;
|
||||
myErrorCount = 0;
|
||||
myProceedCount = 0;
|
||||
myMatchedCount = 0;
|
||||
myCompletionReason = null;
|
||||
}
|
||||
|
||||
private void setProgressBarVisible(boolean value) {
|
||||
myProgressPanel.setVisible(value);
|
||||
}
|
||||
|
||||
private String getDescription() {
|
||||
int total = myProgressBar.getMaximum();
|
||||
String itemsInfo = String.format("Shown: %d / %d", myMatchedCount, total);
|
||||
if (myIsInProcess || myCompletionReason == null) {
|
||||
return itemsInfo;
|
||||
}
|
||||
|
||||
switch (myCompletionReason) {
|
||||
case ALL_CHECKED:
|
||||
break;
|
||||
case INTERRUPTED:
|
||||
itemsInfo = String.format("%s (%s)", itemsInfo, INTERRUPTED_LABEL);
|
||||
break;
|
||||
case LIMIT_REACHED:
|
||||
itemsInfo = String.format("%s (%s)", itemsInfo, LIMIT_REACHED_LABEL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!myIsInProcess && myErrorCount != 0) {
|
||||
String errors = String.format("Errors: %d", myErrorCount);
|
||||
return String.format("<html>%s<br>%s</html>", itemsInfo, errors);
|
||||
}
|
||||
|
||||
return itemsInfo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.debugger.ui.impl.watch.NodeDescriptorProvider;
|
||||
import com.intellij.debugger.ui.tree.NodeDescriptor;
|
||||
import com.intellij.debugger.ui.tree.ValueDescriptor;
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
|
||||
import com.intellij.xdebugger.frame.*;
|
||||
import com.intellij.xdebugger.impl.actions.XDebuggerActions;
|
||||
import com.intellij.xdebugger.impl.frame.XValueMarkers;
|
||||
import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
|
||||
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
|
||||
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeState;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.Value;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class InstancesTree extends XDebuggerTree {
|
||||
public static final DataKey<XDebugSession> DEBUG_SESSION_DATA_KEY = DataKey.create("InstancesTree.DebugSession");
|
||||
private final XValueNodeImpl myRoot;
|
||||
private final Runnable myOnRootExpandAction;
|
||||
private final XDebugSession myDebugSession;
|
||||
private List<XValueChildrenList> myChildren;
|
||||
|
||||
InstancesTree(@NotNull Project project,
|
||||
@NotNull XDebugSession debugSession,
|
||||
@NotNull XDebuggerEditorsProvider editorsProvider,
|
||||
@Nullable XValueMarkers<?, ?> valueMarkers,
|
||||
@NotNull Runnable onRootExpand) {
|
||||
super(project, editorsProvider, null, XDebuggerActions.INSPECT_TREE_POPUP_GROUP, valueMarkers);
|
||||
myOnRootExpandAction = onRootExpand;
|
||||
myRoot = new XValueNodeImpl(this, null, "root", new MyRootValue());
|
||||
myDebugSession = debugSession;
|
||||
|
||||
myRoot.children();
|
||||
setRoot(myRoot, false);
|
||||
myRoot.setLeaf(false);
|
||||
setSelectionRow(0);
|
||||
expandNodesOnLoad(node -> node == myRoot);
|
||||
}
|
||||
|
||||
void addChildren(@NotNull XValueChildrenList children, boolean last) {
|
||||
if (myChildren == null) {
|
||||
myChildren = new ArrayList<>();
|
||||
}
|
||||
|
||||
myChildren.add(children);
|
||||
myRoot.addChildren(children, last);
|
||||
}
|
||||
|
||||
void rebuildTree(@NotNull RebuildPolicy policy, @NotNull XDebuggerTreeState state) {
|
||||
if (policy == RebuildPolicy.RELOAD_INSTANCES) {
|
||||
myChildren = null;
|
||||
}
|
||||
|
||||
rebuildAndRestore(state);
|
||||
}
|
||||
|
||||
void rebuildTree(@NotNull RebuildPolicy policy) {
|
||||
rebuildTree(policy, XDebuggerTreeState.saveState(this));
|
||||
}
|
||||
|
||||
void setInfoMessage(@SuppressWarnings("SameParameterValue") @NotNull String text) {
|
||||
myChildren = null;
|
||||
myRoot.clearChildren();
|
||||
myRoot.setMessage(text, XDebuggerUIConstants.INFORMATION_MESSAGE_ICON, SimpleTextAttributes.REGULAR_ATTRIBUTES, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
ObjectReference getSelectedReference() {
|
||||
TreePath selectionPath = getSelectionPath();
|
||||
Object selectedItem = selectionPath != null ? selectionPath.getLastPathComponent() : null;
|
||||
if (selectedItem instanceof XValueNodeImpl) {
|
||||
XValueNodeImpl xValueNode = (XValueNodeImpl) selectedItem;
|
||||
XValue valueContainer = xValueNode.getValueContainer();
|
||||
|
||||
if (valueContainer instanceof NodeDescriptorProvider) {
|
||||
NodeDescriptor descriptor = ((NodeDescriptorProvider) valueContainer).getDescriptor();
|
||||
|
||||
if (descriptor instanceof ValueDescriptor) {
|
||||
Value value = ((ValueDescriptor) descriptor).getValue();
|
||||
|
||||
if (value instanceof ObjectReference) return (ObjectReference) value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getData(@NonNls String dataId) {
|
||||
if (DEBUG_SESSION_DATA_KEY.is(dataId)) {
|
||||
return myDebugSession;
|
||||
}
|
||||
|
||||
return super.getData(dataId);
|
||||
}
|
||||
|
||||
enum RebuildPolicy {
|
||||
RELOAD_INSTANCES, ONLY_UPDATE_LABELS
|
||||
}
|
||||
|
||||
private class MyRootValue extends XValue {
|
||||
@Override
|
||||
public void computeChildren(@NotNull XCompositeNode node) {
|
||||
if (myChildren == null) {
|
||||
myOnRootExpandAction.run();
|
||||
} else {
|
||||
for (XValueChildrenList children : myChildren) {
|
||||
myRoot.addChildren(children, false);
|
||||
}
|
||||
|
||||
myRoot.addChildren(XValueChildrenList.EMPTY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computePresentation(@NotNull XValueNode node, @NotNull XValuePlace place) {
|
||||
node.setPresentation(null, "", "", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.debugger.DebuggerManager;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.JavaValue;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContext;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
|
||||
import com.intellij.debugger.memory.filtering.FilteringResult;
|
||||
import com.intellij.debugger.memory.filtering.FilteringTask;
|
||||
import com.intellij.debugger.memory.filtering.FilteringTaskCallback;
|
||||
import com.intellij.debugger.memory.utils.*;
|
||||
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.MessageDescriptor;
|
||||
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
|
||||
import com.intellij.debugger.ui.tree.NodeDescriptor;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.AnActionListener;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.ui.DoubleClickListener;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.JBPanel;
|
||||
import com.intellij.util.ui.JBDimension;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.update.UiNotifyConnector;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebugSessionListener;
|
||||
import com.intellij.xdebugger.XExpression;
|
||||
import com.intellij.xdebugger.frame.XValue;
|
||||
import com.intellij.xdebugger.frame.XValueChildrenList;
|
||||
import com.intellij.xdebugger.impl.XDebugSessionImpl;
|
||||
import com.intellij.xdebugger.impl.actions.XDebuggerActionBase;
|
||||
import com.intellij.xdebugger.impl.frame.XValueMarkers;
|
||||
import com.intellij.xdebugger.impl.ui.XDebuggerExpressionEditor;
|
||||
import com.intellij.xdebugger.impl.ui.tree.ValueMarkup;
|
||||
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeState;
|
||||
import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.java.debugger.JavaDebuggerEditorsProvider;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class InstancesWindow extends DialogWrapper {
|
||||
private static final Logger LOG = Logger.getInstance(InstancesWindow.class);
|
||||
|
||||
private static final int DEFAULT_WINDOW_WIDTH = 870;
|
||||
private static final int DEFAULT_WINDOW_HEIGHT = 400;
|
||||
private static final int FILTERING_BUTTON_ADDITIONAL_WIDTH = 30;
|
||||
private static final int BORDER_LAYOUT_DEFAULT_GAP = 5;
|
||||
private static final int DEFAULT_INSTANCES_LIMIT = 500000;
|
||||
|
||||
private final Project myProject;
|
||||
private final XDebugSession myDebugSession;
|
||||
private final InstancesProvider myInstancesProvider;
|
||||
private final String myClassName;
|
||||
private MyInstancesView myInstancesView;
|
||||
|
||||
public InstancesWindow(@NotNull XDebugSession session,
|
||||
@NotNull InstancesProvider provider,
|
||||
@NotNull String className) {
|
||||
super(session.getProject(), false);
|
||||
|
||||
myProject = session.getProject();
|
||||
myDebugSession = session;
|
||||
myInstancesProvider = provider;
|
||||
myClassName = className;
|
||||
|
||||
addWarningMessage(null);
|
||||
myDebugSession.addSessionListener(new XDebugSessionListener() {
|
||||
@Override
|
||||
public void sessionStopped() {
|
||||
ApplicationManager.getApplication().invokeLater(() -> close(OK_EXIT_CODE));
|
||||
}
|
||||
}, myDisposable);
|
||||
setModal(false);
|
||||
init();
|
||||
JRootPane root = myInstancesView.getRootPane();
|
||||
root.setDefaultButton(myInstancesView.myFilterButton);
|
||||
}
|
||||
|
||||
private void addWarningMessage(@Nullable String message) {
|
||||
String warning = message == null ? "" : String.format(". Warning: %s", message);
|
||||
setTitle(String.format("Instances of %s%s", myClassName, warning));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getDimensionServiceKey() {
|
||||
return "#org.jetbrains.debugger.memory.view.InstancesWindow";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
myInstancesView = new MyInstancesView();
|
||||
myInstancesView.setPreferredSize(
|
||||
new JBDimension(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT));
|
||||
return myInstancesView;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createSouthPanel() {
|
||||
JComponent comp = super.createSouthPanel();
|
||||
if (comp != null) {
|
||||
comp.add(myInstancesView.myProgress, BorderLayout.WEST);
|
||||
}
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Action[] createActions() {
|
||||
return new Action[]{new DialogWrapperExitAction("Close", CLOSE_EXIT_CODE)};
|
||||
}
|
||||
|
||||
private class MyInstancesView extends JBPanel implements Disposable {
|
||||
private static final int MAX_TREE_NODE_COUNT = 2000;
|
||||
private static final int FILTERING_CHUNK_SIZE = 50;
|
||||
|
||||
private static final int MAX_DURATION_TO_UPDATE_TREE_SECONDS = 3;
|
||||
private static final int FILTERING_PROGRESS_UPDATING_MIN_DELAY_MILLIS = 17; // ~ 60 fps
|
||||
|
||||
private final InstancesTree myInstancesTree;
|
||||
private final XDebuggerExpressionEditor myFilterConditionEditor;
|
||||
private final XDebugSessionListener myDebugSessionListener = new MySessionListener();
|
||||
|
||||
private final MyNodeManager myNodeManager = new MyNodeManager(myProject);
|
||||
|
||||
private final JButton myFilterButton = new JButton("Filter");
|
||||
private final FilteringProgressView myProgress = new FilteringProgressView();
|
||||
|
||||
private final AnActionListener.Adapter myActionListener = new MyActionListener();
|
||||
private final Object myFilteringTaskLock = new Object();
|
||||
|
||||
private boolean myIsAndroidVM = false;
|
||||
|
||||
private volatile MyFilteringWorker myFilteringTask = null;
|
||||
|
||||
MyInstancesView() {
|
||||
super(new BorderLayout(0, JBUI.scale(BORDER_LAYOUT_DEFAULT_GAP)));
|
||||
|
||||
Disposer.register(InstancesWindow.this.myDisposable, this);
|
||||
XValueMarkers<?, ?> markers = getValueMarkers();
|
||||
ActionManager.getInstance().addAnActionListener(myActionListener, InstancesWindow.this.myDisposable);
|
||||
myDebugSession.addSessionListener(myDebugSessionListener, InstancesWindow.this.myDisposable);
|
||||
JavaDebuggerEditorsProvider editorsProvider = new JavaDebuggerEditorsProvider();
|
||||
|
||||
myFilterConditionEditor = new ExpressionEditorWithHistory(myProject, myClassName,
|
||||
editorsProvider, InstancesWindow.this.myDisposable);
|
||||
|
||||
myFilterButton.setBorder(BorderFactory.createEmptyBorder());
|
||||
Dimension filteringButtonSize = myFilterConditionEditor.getEditorComponent().getPreferredSize();
|
||||
filteringButtonSize.width = JBUI.scale(FILTERING_BUTTON_ADDITIONAL_WIDTH) +
|
||||
myFilterButton.getPreferredSize().width;
|
||||
myFilterButton.setPreferredSize(filteringButtonSize);
|
||||
|
||||
JBPanel filteringPane = new JBPanel(new BorderLayout(JBUI.scale(BORDER_LAYOUT_DEFAULT_GAP), 0));
|
||||
JBLabel sideEffectsWarning = new JBLabel("Warning: filtering may have side effects", SwingConstants.RIGHT);
|
||||
sideEffectsWarning.setBorder(JBUI.Borders.empty(1, 0, 0, 0));
|
||||
sideEffectsWarning.setComponentStyle(UIUtil.ComponentStyle.SMALL);
|
||||
sideEffectsWarning.setFontColor(UIUtil.FontColor.BRIGHTER);
|
||||
|
||||
filteringPane.add(new JBLabel("Condition:"), BorderLayout.WEST);
|
||||
filteringPane.add(myFilterConditionEditor.getComponent(), BorderLayout.CENTER);
|
||||
filteringPane.add(myFilterButton, BorderLayout.EAST);
|
||||
filteringPane.add(sideEffectsWarning, BorderLayout.SOUTH);
|
||||
|
||||
myProgress.addStopActionListener(this::cancelFilteringTask);
|
||||
|
||||
myInstancesTree = new InstancesTree(myProject, myDebugSession, editorsProvider, markers, this::updateInstances);
|
||||
|
||||
myFilterButton.addActionListener(e -> {
|
||||
String expression = myFilterConditionEditor.getExpression().getExpression();
|
||||
if (!expression.isEmpty()) {
|
||||
myFilterConditionEditor.saveTextInHistory();
|
||||
}
|
||||
|
||||
myFilterButton.setEnabled(false);
|
||||
myInstancesTree.rebuildTree(InstancesTree.RebuildPolicy.RELOAD_INSTANCES);
|
||||
});
|
||||
|
||||
|
||||
StackFrameList list = new StackFrameList(myProject,
|
||||
Collections.emptyList(),
|
||||
GlobalSearchScope.allScope(myProject));
|
||||
|
||||
list.addListSelectionListener(e -> list.navigateToSelectedValue(false));
|
||||
new DoubleClickListener() {
|
||||
@Override
|
||||
protected boolean onDoubleClick(MouseEvent event) {
|
||||
list.navigateToSelectedValue(true);
|
||||
return true;
|
||||
}
|
||||
}.installOn(list);
|
||||
|
||||
InstancesWithStackFrameView instancesWithStackFrame = new InstancesWithStackFrameView(myDebugSession,
|
||||
myInstancesTree, list, myClassName);
|
||||
|
||||
add(filteringPane, BorderLayout.NORTH);
|
||||
add(instancesWithStackFrame.getComponent(), BorderLayout.CENTER);
|
||||
|
||||
JComponent focusedComponent = myFilterConditionEditor.getEditorComponent();
|
||||
UiNotifyConnector.doWhenFirstShown(focusedComponent, () ->
|
||||
IdeFocusManager.findInstanceByComponent(focusedComponent)
|
||||
.requestFocus(focusedComponent, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
cancelFilteringTask();
|
||||
Disposer.dispose(myInstancesTree);
|
||||
}
|
||||
|
||||
private void updateInstances() {
|
||||
DebugProcessImpl debugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject)
|
||||
.getDebugProcess(myDebugSession.getDebugProcess().getProcessHandler());
|
||||
|
||||
cancelFilteringTask();
|
||||
|
||||
debugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(debugProcess.getDebuggerContext()) {
|
||||
@Override
|
||||
public Priority getPriority() {
|
||||
return Priority.LOWEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void threadAction(@NotNull SuspendContextImpl suspendContext) {
|
||||
myIsAndroidVM = AndroidUtil.isAndroidVM(debugProcess.getVirtualMachineProxy().getVirtualMachine());
|
||||
int limit = myIsAndroidVM
|
||||
? AndroidUtil.ANDROID_INSTANCES_LIMIT
|
||||
: DEFAULT_INSTANCES_LIMIT;
|
||||
List<ObjectReference> instances = myInstancesProvider.getInstances(limit + 1);
|
||||
|
||||
EvaluationContextImpl evaluationContext = debugProcess
|
||||
.getDebuggerContext().createEvaluationContext();
|
||||
|
||||
if (instances.size() > limit) {
|
||||
addWarningMessage(String.format("Not all instances will be loaded (only %d)", limit));
|
||||
instances = instances.subList(0, limit);
|
||||
}
|
||||
|
||||
if (evaluationContext != null) {
|
||||
synchronized (myFilteringTaskLock) {
|
||||
myFilteringTask = new MyFilteringWorker(instances, myFilterConditionEditor.getExpression(), evaluationContext);
|
||||
myFilteringTask.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void cancelFilteringTask() {
|
||||
if (myFilteringTask != null) {
|
||||
synchronized (myFilteringTaskLock) {
|
||||
if (myFilteringTask != null) {
|
||||
myFilteringTask.cancel();
|
||||
myFilteringTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private XValueMarkers<?, ?> getValueMarkers() {
|
||||
return myDebugSession instanceof XDebugSessionImpl
|
||||
? ((XDebugSessionImpl)myDebugSession).getValueMarkers()
|
||||
: null;
|
||||
}
|
||||
|
||||
private class MySessionListener implements XDebugSessionListener {
|
||||
private volatile XDebuggerTreeState myTreeState = null;
|
||||
|
||||
@Override
|
||||
public void sessionResumed() {
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
myTreeState = XDebuggerTreeState.saveState(myInstancesTree);
|
||||
cancelFilteringTask();
|
||||
|
||||
myInstancesTree.setInfoMessage(
|
||||
"The application is running");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionPaused() {
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
myProgress.setVisible(true);
|
||||
myInstancesTree.rebuildTree(InstancesTree.RebuildPolicy.RELOAD_INSTANCES, myTreeState);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class MyActionListener extends AnActionListener.Adapter {
|
||||
@Override
|
||||
public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
|
||||
if (dataContext.getData(PlatformDataKeys.CONTEXT_COMPONENT) == myInstancesView.myInstancesTree &&
|
||||
(isAddToWatchesAction(action) || isEvaluateExpressionAction(action))) {
|
||||
final XValueNodeImpl selectedNode = XDebuggerTreeActionBase.getSelectedNode(dataContext);
|
||||
final XValueMarkers<?, ?> markers = getValueMarkers();
|
||||
|
||||
if (markers != null && selectedNode != null) {
|
||||
|
||||
TreeNode currentNode = selectedNode;
|
||||
while (!myInstancesTree.getRoot().equals(currentNode.getParent())) {
|
||||
currentNode = currentNode.getParent();
|
||||
}
|
||||
|
||||
final XValue valueContainer = ((XValueNodeImpl)currentNode).getValueContainer();
|
||||
|
||||
final String expression = valueContainer.getEvaluationExpression();
|
||||
if (expression != null) {
|
||||
markers.markValue(valueContainer,
|
||||
new ValueMarkup(expression.replace("@", ""), new JBColor(0, 0), null));
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(() -> myInstancesTree
|
||||
.rebuildTree(InstancesTree.RebuildPolicy.ONLY_UPDATE_LABELS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAddToWatchesAction(AnAction action) {
|
||||
final String className = action.getClass().getSimpleName();
|
||||
return action instanceof XDebuggerTreeActionBase && className.equals("XAddToWatchesAction");
|
||||
}
|
||||
|
||||
private boolean isEvaluateExpressionAction(AnAction action) {
|
||||
final String className = action.getClass().getSimpleName();
|
||||
return action instanceof XDebuggerActionBase && className.equals("EvaluateAction");
|
||||
}
|
||||
}
|
||||
|
||||
private class MyFilteringCallback implements FilteringTaskCallback {
|
||||
private final ErrorsValueGroup myErrorsGroup = new ErrorsValueGroup();
|
||||
private final EvaluationContextImpl myEvaluationContext;
|
||||
|
||||
private long myFilteringStartedTime;
|
||||
|
||||
private int myProceedCount = 0;
|
||||
private int myMatchedCount = 0;
|
||||
private int myErrorsCount = 0;
|
||||
|
||||
private long myLastTreeUpdatingTime;
|
||||
private long myLastProgressUpdatingTime;
|
||||
|
||||
public MyFilteringCallback(@NotNull EvaluationContextImpl evaluationContext) {
|
||||
myEvaluationContext = evaluationContext;
|
||||
}
|
||||
|
||||
private XValueChildrenList myChildren = new XValueChildrenList();
|
||||
|
||||
@Override
|
||||
public void started(int total) {
|
||||
myFilteringStartedTime = System.nanoTime();
|
||||
myLastTreeUpdatingTime = myFilteringStartedTime;
|
||||
myLastProgressUpdatingTime = System.nanoTime();
|
||||
ApplicationManager.getApplication().invokeLater(() -> myProgress.start(total));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Action matched(@NotNull ObjectReference ref) {
|
||||
final JavaValue val = new InstanceJavaValue(new InstanceValueDescriptor(myProject, ref),
|
||||
myEvaluationContext, myNodeManager);
|
||||
myMatchedCount++;
|
||||
myProceedCount++;
|
||||
myChildren.add(val);
|
||||
updateProgress();
|
||||
updateTree();
|
||||
|
||||
return myMatchedCount < MAX_TREE_NODE_COUNT ? Action.CONTINUE : Action.STOP;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Action notMatched(@NotNull ObjectReference ref) {
|
||||
myProceedCount++;
|
||||
updateProgress();
|
||||
|
||||
return Action.CONTINUE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Action error(@NotNull ObjectReference ref, @NotNull String description) {
|
||||
final JavaValue val = new InstanceJavaValue(new InstanceValueDescriptor(myProject, ref),
|
||||
myEvaluationContext, myNodeManager);
|
||||
myErrorsGroup.addErrorValue(description, val);
|
||||
myProceedCount++;
|
||||
myErrorsCount++;
|
||||
updateProgress();
|
||||
return Action.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(@NotNull FilteringResult reason) {
|
||||
if (!myErrorsGroup.isEmpty()) {
|
||||
myChildren.addBottomGroup(myErrorsGroup);
|
||||
}
|
||||
|
||||
final long duration = System.nanoTime() - myFilteringStartedTime;
|
||||
LOG.info(String.format("Filtering completed in %d ms for %d instances",
|
||||
TimeUnit.NANOSECONDS.toMillis(duration),
|
||||
myProceedCount));
|
||||
|
||||
final int proceed = myProceedCount;
|
||||
final int matched = myMatchedCount;
|
||||
final int errors = myErrorsCount;
|
||||
final XValueChildrenList childrenList = myChildren;
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
myProgress.updateProgress(proceed, matched, errors);
|
||||
myInstancesTree.addChildren(childrenList, true);
|
||||
myFilterButton.setEnabled(true);
|
||||
myProgress.complete(reason);
|
||||
});
|
||||
}
|
||||
|
||||
private void updateProgress() {
|
||||
final long now = System.nanoTime();
|
||||
if (now - myLastProgressUpdatingTime > TimeUnit.MILLISECONDS.toNanos(FILTERING_PROGRESS_UPDATING_MIN_DELAY_MILLIS)) {
|
||||
final int proceed = myProceedCount;
|
||||
final int matched = myMatchedCount;
|
||||
final int errors = myErrorsCount;
|
||||
ApplicationManager.getApplication().invokeLater(() -> myProgress.updateProgress(proceed, matched, errors));
|
||||
myLastProgressUpdatingTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTree() {
|
||||
final long now = System.nanoTime();
|
||||
final int newChildrenCount = myChildren.size();
|
||||
if (newChildrenCount >= FILTERING_CHUNK_SIZE ||
|
||||
(newChildrenCount > 0 && now - myLastTreeUpdatingTime > TimeUnit.SECONDS.toNanos(MAX_DURATION_TO_UPDATE_TREE_SECONDS))) {
|
||||
final XValueChildrenList children = myChildren;
|
||||
ApplicationManager.getApplication().invokeLater(() -> myInstancesTree.addChildren(children, false));
|
||||
myChildren = new XValueChildrenList();
|
||||
myLastTreeUpdatingTime = System.nanoTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyFilteringWorker extends SwingWorker<Void, Void> {
|
||||
private final FilteringTask myTask;
|
||||
|
||||
MyFilteringWorker(@NotNull List<ObjectReference> refs,
|
||||
@NotNull XExpression expression,
|
||||
@NotNull EvaluationContextImpl evaluationContext) {
|
||||
if (refs.size() != 0) {
|
||||
DebugProcessImpl debugProcess =
|
||||
(DebugProcessImpl)DebuggerManager.getInstance(myProject).getDebugProcess(myDebugSession.getDebugProcess().getProcessHandler());
|
||||
myTask = new FilteringTask(refs.get(0).referenceType(), debugProcess, expression, refs,
|
||||
new MyFilteringCallback(evaluationContext));
|
||||
}
|
||||
else {
|
||||
myTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
if (myTask != null) {
|
||||
myTask.run();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
myTask.cancel();
|
||||
super.cancel(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final static class MyNodeManager extends NodeManagerImpl {
|
||||
MyNodeManager(Project project) {
|
||||
super(project, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebuggerTreeNodeImpl createNode(final NodeDescriptor descriptor, EvaluationContext evaluationContext) {
|
||||
return new DebuggerTreeNodeImpl(null, descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebuggerTreeNodeImpl createMessageNode(MessageDescriptor descriptor) {
|
||||
return new DebuggerTreeNodeImpl(null, descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebuggerTreeNodeImpl createMessageNode(String message) {
|
||||
return new DebuggerTreeNodeImpl(null, new MessageDescriptor(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.ui.JBSplitter;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.ui.components.labels.ActionLink;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.intellij.debugger.memory.component.CreationPositionTracker;
|
||||
import com.intellij.debugger.memory.component.InstancesTracker;
|
||||
import com.intellij.debugger.memory.event.InstancesTrackerListener;
|
||||
import com.intellij.debugger.memory.tracking.TrackingType;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
class InstancesWithStackFrameView {
|
||||
private static final float DEFAULT_SPLITTER_PROPORTION = 0.7f;
|
||||
private static final String EMPTY_TEXT_WHEN_ITEM_NOT_SELECTED = "Select instance to see stack frame";
|
||||
private static final String EMPTY_TEXT_WHEN_STACK_NOT_FOUND = "No stack frame for this instance";
|
||||
private static final String TEXT_FOR_ARRAYS = "Arrays could not be tracked";
|
||||
private static final List<StackFrameItem> EMPTY_FRAME = Collections.emptyList();
|
||||
|
||||
private float myHidedProportion;
|
||||
|
||||
private final JBSplitter mySplitter = new JBSplitter(false, DEFAULT_SPLITTER_PROPORTION);
|
||||
private boolean myIsHided = false;
|
||||
|
||||
InstancesWithStackFrameView(@NotNull XDebugSession debugSession, @NotNull InstancesTree tree,
|
||||
@NotNull StackFrameList list, String className) {
|
||||
mySplitter.setFirstComponent(new JBScrollPane(tree));
|
||||
|
||||
list.setEmptyText(EMPTY_TEXT_WHEN_ITEM_NOT_SELECTED);
|
||||
JLabel stackTraceLabel;
|
||||
if (isArrayType(className)) {
|
||||
stackTraceLabel = new JBLabel(TEXT_FOR_ARRAYS, SwingConstants.CENTER);
|
||||
}
|
||||
else {
|
||||
ActionLink actionLink = new ActionLink("Enable tracking for new instances",
|
||||
AllIcons.Debugger.MemoryView.ClassTracked,
|
||||
new AnAction() {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
InstancesTracker.getInstance(debugSession.getProject())
|
||||
.add(className, TrackingType.CREATION);
|
||||
}
|
||||
});
|
||||
|
||||
actionLink.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
actionLink.setPaintUnderline(false);
|
||||
stackTraceLabel = actionLink;
|
||||
}
|
||||
|
||||
mySplitter.setSplitterProportionKey("InstancesWithStackFrameView.SplitterKey");
|
||||
|
||||
JComponent stackComponent = new JBScrollPane(list);
|
||||
|
||||
CreationPositionTracker tracker = CreationPositionTracker.getInstance(debugSession.getProject());
|
||||
InstancesTracker instancesTracker = InstancesTracker.getInstance(debugSession.getProject());
|
||||
instancesTracker.addTrackerListener(new InstancesTrackerListener() {
|
||||
@Override
|
||||
public void classChanged(@NotNull String name, @NotNull TrackingType type) {
|
||||
if (Objects.equals(className, name) && type == TrackingType.CREATION) {
|
||||
mySplitter.setSecondComponent(stackComponent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classRemoved(@NotNull String name) {
|
||||
if (Objects.equals(name, className)) {
|
||||
mySplitter.setSecondComponent(stackTraceLabel);
|
||||
}
|
||||
}
|
||||
}, tree);
|
||||
|
||||
mySplitter.setSecondComponent(instancesTracker.isTracked(className) ? stackComponent : stackTraceLabel);
|
||||
|
||||
mySplitter.setHonorComponentsMinimumSize(false);
|
||||
myHidedProportion = DEFAULT_SPLITTER_PROPORTION;
|
||||
|
||||
tree.addTreeSelectionListener(e -> {
|
||||
ObjectReference ref = tree.getSelectedReference();
|
||||
if (ref != null && tracker != null) {
|
||||
List<StackFrameItem> stack = tracker.getStack(debugSession, ref);
|
||||
if (stack != null) {
|
||||
list.setFrame(stack);
|
||||
if (mySplitter.getProportion() == 1.f) {
|
||||
mySplitter.setProportion(DEFAULT_SPLITTER_PROPORTION);
|
||||
}
|
||||
return;
|
||||
}
|
||||
list.setEmptyText(EMPTY_TEXT_WHEN_STACK_NOT_FOUND);
|
||||
}
|
||||
else {
|
||||
list.setEmptyText(EMPTY_TEXT_WHEN_ITEM_NOT_SELECTED);
|
||||
}
|
||||
|
||||
list.setFrame(EMPTY_FRAME);
|
||||
});
|
||||
}
|
||||
|
||||
JComponent getComponent() {
|
||||
return mySplitter;
|
||||
}
|
||||
|
||||
private static boolean isArrayType(@NotNull String className) {
|
||||
return className.contains("[]");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void hideStackFrame() {
|
||||
if (!myIsHided) {
|
||||
myHidedProportion = mySplitter.getProportion();
|
||||
mySplitter.getSecondComponent().setVisible(false);
|
||||
mySplitter.setProportion(1.f);
|
||||
myIsHided = true;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void showStackFrame() {
|
||||
if (myIsHided) {
|
||||
mySplitter.getSecondComponent().setVisible(true);
|
||||
mySplitter.setProportion(myHidedProportion);
|
||||
myIsHided = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.debugger.engine.DebuggerUtils;
|
||||
import com.intellij.execution.filters.OpenFileHyperlinkInfo;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.ColoredListCellRenderer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class StackFrameList extends JBList<StackFrameItem> {
|
||||
private static final char ANONYMOUS_CLASS_DELIMITER = '$';
|
||||
private static final MyOpenFilesState myEditorState = new MyOpenFilesState();
|
||||
|
||||
private List<StackFrameItem> myStackFrames;
|
||||
private final Project myProject;
|
||||
private final GlobalSearchScope myScope;
|
||||
private final MyListModel myModel = new MyListModel();
|
||||
|
||||
StackFrameList(@NotNull Project project,
|
||||
@NotNull List<StackFrameItem> stack,
|
||||
@NotNull GlobalSearchScope searchScope) {
|
||||
super();
|
||||
|
||||
myStackFrames = new ArrayList<>(stack);
|
||||
myProject = project;
|
||||
myScope = searchScope;
|
||||
|
||||
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
setModel(myModel);
|
||||
|
||||
setCellRenderer(new ColoredListCellRenderer<StackFrameItem>() {
|
||||
@Override
|
||||
protected void customizeCellRenderer(@NotNull JList<? extends StackFrameItem> list,
|
||||
StackFrameItem value, int index, boolean isSelected, boolean hasFocus) {
|
||||
append(String.format("%s:%d, %s", value.methodName(), value.line(), value.className()));
|
||||
String packageName = value.packageName();
|
||||
if (packageName.trim().isEmpty() /*!StringUtils.isEmpty(packageName)*/) {
|
||||
append(String.format(" (%s)", value.packageName()), SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setFrame(@NotNull List<StackFrameItem> stack) {
|
||||
myModel.update(stack);
|
||||
}
|
||||
|
||||
void navigateToSelectedValue(boolean focusOnEditor) {
|
||||
StackFrameItem selectedValue = getSelectedValue();
|
||||
if (selectedValue != null) {
|
||||
navigateToFrame(selectedValue, focusOnEditor);
|
||||
}
|
||||
}
|
||||
|
||||
private void navigateToFrame(@NotNull StackFrameItem frame, boolean focusOnEditor) {
|
||||
String path = frame.path();
|
||||
int anonymousClassDelimiterIndex = path.indexOf(ANONYMOUS_CLASS_DELIMITER);
|
||||
int pathLength = anonymousClassDelimiterIndex > 0 ? anonymousClassDelimiterIndex : path.length();
|
||||
path = path.substring(0, pathLength);
|
||||
PsiClass psiClass = DebuggerUtils.findClass(path, myProject, myScope);
|
||||
if (psiClass != null) {
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
PsiElement navigationElement = psiClass.getNavigationElement();
|
||||
VirtualFile file = PsiUtilCore.getVirtualFile(navigationElement);
|
||||
|
||||
if (file == null) {
|
||||
file = psiClass.getContainingFile().getVirtualFile();
|
||||
}
|
||||
|
||||
OpenFileHyperlinkInfo info =
|
||||
new OpenFileHyperlinkInfo(myProject, file, frame.line() - 1);
|
||||
OpenFileDescriptor descriptor = info.getDescriptor();
|
||||
if (descriptor != null) {
|
||||
FileEditorManagerImpl manager = (FileEditorManagerImpl)FileEditorManager.getInstance(myProject);
|
||||
VirtualFile lastFile = myEditorState.myLastOpenedFile;
|
||||
if (myEditorState.myIsNeedToCloseLastOpenedFile && lastFile != null &&
|
||||
manager.isFileOpen(lastFile) && !lastFile.equals(descriptor.getFile())) {
|
||||
manager.closeFile(myEditorState.myLastOpenedFile, false, true);
|
||||
}
|
||||
|
||||
descriptor.setScrollType(ScrollType.CENTER);
|
||||
descriptor.setUseCurrentWindow(true);
|
||||
|
||||
if (lastFile == null || !lastFile.equals(descriptor.getFile())) {
|
||||
myEditorState.myIsNeedToCloseLastOpenedFile = !manager.isFileOpen(descriptor.getFile());
|
||||
}
|
||||
|
||||
descriptor.navigateInEditor(myProject, focusOnEditor);
|
||||
FileEditor[] editors = manager.getEditors(descriptor.getFile());
|
||||
if (editors.length != 0) {
|
||||
myEditorState.myLastOpenedFile = descriptor.getFile();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyOpenFilesState {
|
||||
VirtualFile myLastOpenedFile;
|
||||
boolean myIsNeedToCloseLastOpenedFile;
|
||||
}
|
||||
|
||||
private class MyListModel extends AbstractListModel<StackFrameItem> {
|
||||
|
||||
void update(@NotNull List<StackFrameItem> newFrame) {
|
||||
fireIntervalRemoved(this, 0, getSize());
|
||||
myStackFrames = newFrame;
|
||||
fireIntervalAdded(this, 0, getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return myStackFrames.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackFrameItem getElementAt(int index) {
|
||||
return myStackFrames.get(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StackFramePopup {
|
||||
private final Project myProject;
|
||||
private final List<StackFrameItem> myStackFrame;
|
||||
private final GlobalSearchScope myScope;
|
||||
|
||||
public StackFramePopup(@NotNull Project project,
|
||||
@NotNull List<StackFrameItem> stack,
|
||||
@NotNull GlobalSearchScope searchScope) {
|
||||
myProject = project;
|
||||
myStackFrame = stack;
|
||||
myScope = searchScope;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
StackFrameList list = new StackFrameList(myProject, myStackFrame, myScope);
|
||||
list.addListSelectionListener(e -> {
|
||||
if (!e.getValueIsAdjusting()) {
|
||||
list.navigateToSelectedValue(false);
|
||||
}
|
||||
});
|
||||
|
||||
JBPopup popup = JBPopupFactory.getInstance().createListPopupBuilder(list)
|
||||
.setTitle("Select stack frame")
|
||||
.setAutoSelectIfEmpty(true)
|
||||
.setResizable(false)
|
||||
.setItemChoosenCallback(() -> list.navigateToSelectedValue(true))
|
||||
.createPopup();
|
||||
|
||||
list.setSelectedIndex(1);
|
||||
popup.showInFocusCenter();
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
public abstract class AbstractTableColumnDescriptor implements AbstractTableModelWithColumns.TableColumnDescriptor {
|
||||
private final String myName;
|
||||
private final Class<?> myClass;
|
||||
protected AbstractTableColumnDescriptor(String name, Class<?> elementClass) {
|
||||
myName = name;
|
||||
myClass = elementClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass() {
|
||||
return myClass;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
public abstract class AbstractTableModelWithColumns extends AbstractTableModel {
|
||||
|
||||
private final TableColumnDescriptor[] myColumnDescriptors;
|
||||
public AbstractTableModelWithColumns(TableColumnDescriptor[] descriptors) {
|
||||
myColumnDescriptors = descriptors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
return myColumnDescriptors[columnIndex].getColumnClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
return myColumnDescriptors[column].getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return myColumnDescriptors.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
return myColumnDescriptors[columnIndex].getValue(rowIndex);
|
||||
}
|
||||
|
||||
interface TableColumnDescriptor {
|
||||
Class<?> getColumnClass();
|
||||
Object getValue(int ix);
|
||||
String getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
import com.sun.jdi.VirtualMachine;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class AndroidUtil {
|
||||
public static final int ANDROID_COUNT_BY_CLASSES_BATCH_SIZE = 500;
|
||||
public static final int ANDROID_INSTANCES_LIMIT = 30000;
|
||||
|
||||
public static boolean isAndroidVM(@NotNull VirtualMachine vm) {
|
||||
return vm.name().toLowerCase(Locale.ENGLISH).contains("dalvik");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.xdebugger.frame.XCompositeNode;
|
||||
import com.intellij.xdebugger.frame.XNamedValue;
|
||||
import com.intellij.xdebugger.frame.XValueChildrenList;
|
||||
import com.intellij.xdebugger.frame.XValueGroup;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ErrorsValueGroup extends XValueGroup {
|
||||
private final Map<String, List<XNamedValue>> myErrorMessage2ValueMap = new HashMap<>();
|
||||
|
||||
public ErrorsValueGroup() {
|
||||
super("Errors");
|
||||
}
|
||||
|
||||
public void addErrorValue(@NotNull String message, @NotNull XNamedValue value) {
|
||||
List<XNamedValue> lst;
|
||||
if (!myErrorMessage2ValueMap.containsKey(message)) {
|
||||
myErrorMessage2ValueMap.put(message, new ArrayList<>());
|
||||
}
|
||||
|
||||
lst = myErrorMessage2ValueMap.get(message);
|
||||
lst.add(value);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return myErrorMessage2ValueMap.isEmpty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return AllIcons.General.Error;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeChildren(@NotNull XCompositeNode node) {
|
||||
XValueChildrenList lst = new XValueChildrenList();
|
||||
myErrorMessage2ValueMap.keySet().forEach(s -> lst.addTopGroup(new MyErrorsValueGroup(s)));
|
||||
node.addChildren(lst, true);
|
||||
}
|
||||
|
||||
private class MyErrorsValueGroup extends XValueGroup {
|
||||
|
||||
@Override
|
||||
public void computeChildren(@NotNull XCompositeNode node) {
|
||||
XValueChildrenList lst = new XValueChildrenList();
|
||||
String name = getName();
|
||||
myErrorMessage2ValueMap.get(name).forEach(lst::add);
|
||||
node.addChildren(lst, true);
|
||||
}
|
||||
|
||||
MyErrorsValueGroup(@NotNull String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
import com.intellij.debugger.engine.JavaValue;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class InstanceJavaValue extends JavaValue {
|
||||
public InstanceJavaValue(@NotNull ValueDescriptorImpl valueDescriptor,
|
||||
@NotNull EvaluationContextImpl evaluationContext,
|
||||
NodeManagerImpl nodeManager) {
|
||||
super(null, valueDescriptor, evaluationContext, nodeManager, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getEvaluationExpression() {
|
||||
ObjectReference ref = ((ObjectReference)getDescriptor().getValue());
|
||||
return NamesUtils.getUniqueName(ref);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigateToSource() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
import com.intellij.debugger.DebuggerContext;
|
||||
import com.intellij.debugger.engine.ContextUtil;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiElementFactory;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.sun.jdi.ArrayReference;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.Value;
|
||||
|
||||
public class InstanceValueDescriptor extends ValueDescriptorImpl {
|
||||
|
||||
public InstanceValueDescriptor(Project project, Value value) {
|
||||
super(project, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String calcValueName() {
|
||||
ObjectReference ref = ((ObjectReference) getValue());
|
||||
if (ref instanceof ArrayReference) {
|
||||
ArrayReference arrayReference = (ArrayReference) ref;
|
||||
return NamesUtils.getArrayUniqueName(arrayReference);
|
||||
}
|
||||
return NamesUtils.getUniqueName(ref);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
|
||||
return getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowIdLabel() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiExpression getDescriptorEvaluation(DebuggerContext debuggerContext) throws EvaluateException {
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myProject).getElementFactory();
|
||||
ObjectReference ref = ((ObjectReference) getValue());
|
||||
String name = NamesUtils.getUniqueName(ref).replace("@", "");
|
||||
String presentation = String.format("%s_DebugLabel", name);
|
||||
|
||||
return elementFactory.createExpressionFromText(presentation, ContextUtil.getContextElement(debuggerContext));
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -13,14 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.jps.javac.ast;
|
||||
package com.intellij.debugger.memory.utils;
|
||||
|
||||
import org.jetbrains.jps.javac.ast.api.JavacDef;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRef;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
interface JavacTreeScannerSink {
|
||||
import java.util.List;
|
||||
|
||||
void sinkReference(JavacRef.JavacSymbolRefBase ref);
|
||||
|
||||
void sinkDeclaration(JavacDef def);
|
||||
public interface InstancesProvider {
|
||||
@NotNull
|
||||
List<ObjectReference> getInstances(int limit);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
public class KeyboardUtils {
|
||||
public static boolean isEnterKey(int keyCode) {
|
||||
return keyCode == KeyEvent.VK_ENTER;
|
||||
}
|
||||
|
||||
public static boolean isUpDownKey(int keyCode) {
|
||||
return keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN;
|
||||
}
|
||||
|
||||
public static boolean isBackSpace(int keyCode) {
|
||||
return keyCode == KeyEvent.VK_BACK_SPACE;
|
||||
}
|
||||
|
||||
public static boolean isCharacter(int keyCode) {
|
||||
return KeyEvent.getKeyText(keyCode).length() == 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class LowestPriorityCommand extends SuspendContextCommandImpl {
|
||||
protected LowestPriorityCommand(@Nullable SuspendContextImpl suspendContext) {
|
||||
super(suspendContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void commandCancelled() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Priority getPriority() {
|
||||
return Priority.LOWEST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.sun.jdi.ArrayReference;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
class NamesUtils {
|
||||
@NotNull
|
||||
static String getUniqueName(@NotNull ObjectReference ref) {
|
||||
String shortName = StringUtil.getShortName(ref.referenceType().name());
|
||||
String name = shortName.replace("[]", "Array");
|
||||
return String.format("%s@%d", name, ref.uniqueID());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static String getArrayUniqueName(@NotNull ArrayReference ref) {
|
||||
String shortName = StringUtil.getShortName(ref.referenceType().name());
|
||||
int length = ref.length();
|
||||
|
||||
String name = shortName.replaceFirst(Pattern.quote("[]"), String.format("[%d]", length));
|
||||
return String.format("%s@%d", name, ref.uniqueID());
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.util.Alarm;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SingleAlarmWithMutableDelay extends Alarm {
|
||||
private final Runnable myTask;
|
||||
private volatile int myDelay;
|
||||
public SingleAlarmWithMutableDelay(@NotNull Runnable task, @NotNull Disposable parentDisposable) {
|
||||
super(ThreadToUse.POOLED_THREAD, parentDisposable);
|
||||
myTask = task;
|
||||
}
|
||||
|
||||
public void setDelay(int value) {
|
||||
myDelay = value;
|
||||
}
|
||||
|
||||
public void cancelAndRequest() {
|
||||
if(!isDisposed()) {
|
||||
cancelAllRequests();
|
||||
addRequest(myTask, myDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.memory.utils;
|
||||
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.sun.jdi.Location;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class StackFrameItem {
|
||||
private final String myFilePath;
|
||||
private final String myMethodName;
|
||||
private final int myLineNumber;
|
||||
|
||||
public StackFrameItem(@NotNull String path, @NotNull String methodName, int line) {
|
||||
myFilePath = path.replace('\\', '.');
|
||||
myMethodName = methodName;
|
||||
myLineNumber = line;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String path() {
|
||||
return myFilePath;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String methodName() {
|
||||
return myMethodName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String className() {
|
||||
return StringUtil.getShortName(myFilePath);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String packageName() {
|
||||
return StringUtil.getPackageName(myFilePath);
|
||||
}
|
||||
|
||||
public int line() {
|
||||
return myLineNumber;
|
||||
}
|
||||
|
||||
public static List<StackFrameItem> createFrames(ThreadReferenceProxyImpl threadReferenceProxy) throws EvaluateException {
|
||||
List<StackFrameProxyImpl> stack = threadReferenceProxy == null ? null : threadReferenceProxy.frames();
|
||||
|
||||
if (stack != null) {
|
||||
return StreamEx.of(stack).map(frame -> {
|
||||
try {
|
||||
Location loc = frame.location();
|
||||
return new StackFrameItem(loc.declaringType().name(), loc.method().name(), loc.lineNumber());
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
return null;
|
||||
}
|
||||
}).nonNull().toList();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
+5
-8
@@ -42,7 +42,6 @@ import com.intellij.util.StringBuilderSpinAllocator;
|
||||
import com.intellij.xdebugger.XDebuggerManager;
|
||||
import com.intellij.xdebugger.XSourcePosition;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpoint;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpointManager;
|
||||
import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
|
||||
import com.intellij.xml.CommonXmlStrings;
|
||||
import com.sun.jdi.Location;
|
||||
@@ -307,7 +306,7 @@ public abstract class BreakpointWithHighlighter<P extends JavaBreakpointProperti
|
||||
*/
|
||||
@Override
|
||||
public final void updateUI() {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
if (!isVisible() || ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return;
|
||||
}
|
||||
DebuggerInvocationUtil.swingInvokeLater(myProject, () -> {
|
||||
@@ -338,11 +337,9 @@ public abstract class BreakpointWithHighlighter<P extends JavaBreakpointProperti
|
||||
}
|
||||
|
||||
private void updateGutter() {
|
||||
if (myVisible) {
|
||||
if (isValid()) {
|
||||
final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(myProject).getBreakpointManager();
|
||||
breakpointManager.updateBreakpointPresentation((XLineBreakpoint)myXBreakpoint, getIcon(), myInvalidMessage);
|
||||
}
|
||||
if (isVisible() && isValid()) {
|
||||
XDebuggerManager.getInstance(myProject).getBreakpointManager()
|
||||
.updateBreakpointPresentation((XLineBreakpoint)myXBreakpoint, getIcon(), myInvalidMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,7 +372,7 @@ public abstract class BreakpointWithHighlighter<P extends JavaBreakpointProperti
|
||||
@Override
|
||||
public abstract Key<? extends BreakpointWithHighlighter> getCategory();
|
||||
|
||||
public boolean isVisible() {
|
||||
protected boolean isVisible() {
|
||||
return myVisible;
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.debugger.ui.breakpoints;
|
||||
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -24,6 +25,7 @@ import com.intellij.psi.PsiManager;
|
||||
import com.intellij.xdebugger.XDebuggerUtil;
|
||||
import com.intellij.xdebugger.XSourcePosition;
|
||||
import com.intellij.xdebugger.breakpoints.XLineBreakpointType;
|
||||
import com.sun.jdi.event.LocatableEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties;
|
||||
@@ -102,7 +104,12 @@ public class RunToCursorBreakpoint extends LineBreakpoint<JavaLineBreakpointProp
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
public String getEventMessage(LocatableEvent event) {
|
||||
return DebuggerBundle.message("status.stopped.at.cursor");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isVisible() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -143,6 +150,9 @@ public class RunToCursorBreakpoint extends LineBreakpoint<JavaLineBreakpointProp
|
||||
@Nullable
|
||||
protected static RunToCursorBreakpoint create(@NotNull Project project, @NotNull XSourcePosition position, boolean restoreBreakpoints) {
|
||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(position.getFile());
|
||||
if (psiFile == null) {
|
||||
return null;
|
||||
}
|
||||
return new RunToCursorBreakpoint(project, SourcePosition.createFromOffset(psiFile, position.getOffset()), restoreBreakpoints);
|
||||
}
|
||||
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 com.intellij.debugger.ui.breakpoints;
|
||||
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.sun.jdi.Value;
|
||||
import com.sun.jdi.event.LocatableEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author egor
|
||||
*/
|
||||
public class StackCapturingLineBreakpoint extends RunToCursorBreakpoint {
|
||||
private final DebugProcessImpl myDebugProcess;
|
||||
private static final Key<Map<Object, List<StackFrameItem>>> CAPTURED_STACKS = Key.create("CAPTURED_STACKS");
|
||||
private static final int MAX_STORED_STACKS = 1000;
|
||||
|
||||
public StackCapturingLineBreakpoint(Project project, DebugProcessImpl debugProcess, @NotNull SourcePosition pos) {
|
||||
super(project, pos, false);
|
||||
myDebugProcess = debugProcess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processLocatableEvent(SuspendContextCommandImpl action, LocatableEvent event) throws EventProcessingException {
|
||||
try {
|
||||
SuspendContextImpl suspendContext = action.getSuspendContext();
|
||||
if (suspendContext != null) {
|
||||
Map<Object, List<StackFrameItem>> stacks = myDebugProcess.getUserData(CAPTURED_STACKS);
|
||||
if (stacks == null) {
|
||||
stacks = new LinkedHashMap<Object, List<StackFrameItem>>() {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry eldest) {
|
||||
return size() > MAX_STORED_STACKS;
|
||||
}
|
||||
};
|
||||
myDebugProcess.putUserData(CAPTURED_STACKS, stacks);
|
||||
}
|
||||
Value key = ContainerUtil.getFirstItem(suspendContext.getFrameProxy().getArgumentValues());
|
||||
stacks.put(key, StackFrameItem.createFrames(suspendContext.getThread()));
|
||||
}
|
||||
}
|
||||
catch (EvaluateException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -79,12 +79,16 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator {
|
||||
public Value evaluate(final EvaluationContext evaluationContext) throws EvaluateException {
|
||||
DebugProcess process = evaluationContext.getDebugProcess();
|
||||
|
||||
ClassLoaderReference classLoader = ClassLoadingUtils.getClassLoader(evaluationContext, process);
|
||||
EvaluationContextImpl autoLoadContext = ((EvaluationContextImpl)evaluationContext).createEvaluationContext(evaluationContext.getThisObject());
|
||||
autoLoadContext.setAutoLoadClasses(true);
|
||||
|
||||
ClassLoaderReference classLoader = ClassLoadingUtils.getClassLoader(autoLoadContext, process);
|
||||
autoLoadContext.setClassLoader(classLoader);
|
||||
|
||||
String version = ((VirtualMachineProxyImpl)process.getVirtualMachineProxy()).version();
|
||||
Collection<ClassObject> classes = compile(JdkVersionUtil.getVersion(version));
|
||||
|
||||
defineClasses(classes, evaluationContext, process, classLoader);
|
||||
defineClasses(classes, autoLoadContext, process, classLoader);
|
||||
|
||||
try {
|
||||
// invoke base evaluator on call code
|
||||
@@ -99,8 +103,7 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator {
|
||||
return factory.getEvaluatorBuilder().build(factory.createCodeFragment(callCode, copyContext, myProject), position);
|
||||
}
|
||||
});
|
||||
((EvaluationContextImpl)evaluationContext).setClassLoader(classLoader);
|
||||
return evaluator.evaluate(evaluationContext);
|
||||
return evaluator.evaluate(autoLoadContext);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new EvaluateException("Error during generated code invocation " + e, e);
|
||||
|
||||
+3
-4
@@ -74,13 +74,12 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl {
|
||||
PsiElement psiContext = ContextUtil.getContextElement(evaluationContext, position);
|
||||
|
||||
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () -> {
|
||||
PsiCodeFragment code = getEvaluationCode(thisEvaluationContext);
|
||||
try {
|
||||
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(getEvaluationText(), psiContext)
|
||||
.getEvaluatorBuilder()
|
||||
.build(getEvaluationCode(thisEvaluationContext), position);
|
||||
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(getEvaluationText(), psiContext).getEvaluatorBuilder().build(code, position);
|
||||
}
|
||||
catch (UnsupportedExpressionException ex) {
|
||||
ExpressionEvaluator eval = CompilingEvaluatorImpl.create(myProject, psiContext, this::createCodeFragment);
|
||||
ExpressionEvaluator eval = CompilingEvaluatorImpl.create(myProject, code.getContext(), element -> code);
|
||||
if (eval != null) {
|
||||
return eval;
|
||||
}
|
||||
|
||||
+5
-6
@@ -74,17 +74,16 @@ public class ExceptionExFilterFactory implements ExceptionFilterFactory {
|
||||
final int lineStartOffset = copiedFragment.getLineStartOffset(i);
|
||||
final int lineEndOffset = copiedFragment.getLineEndOffset(i);
|
||||
|
||||
String text = copiedFragment.getText(new TextRange(lineStartOffset, lineEndOffset));
|
||||
if (!text.contains(".java:")) continue;
|
||||
Trinity<TextRange, TextRange, TextRange> info = visited.get(text);
|
||||
String lineText = copiedFragment.getText(new TextRange(lineStartOffset, lineEndOffset));
|
||||
if (!lineText.contains(".java:")) continue;
|
||||
Trinity<TextRange, TextRange, TextRange> info = visited.get(lineText);
|
||||
if (info == emptyInfo) continue;
|
||||
|
||||
if (info == null) {
|
||||
info = emptyInfo;
|
||||
AccessToken token = ApplicationManager.getApplication().acquireReadActionLock();
|
||||
try {
|
||||
worker.execute(text, lineEndOffset);
|
||||
Result result = worker.getResult();
|
||||
Result result = worker.execute(lineText, lineEndOffset);
|
||||
if (result == null) continue;
|
||||
HyperlinkInfo hyperlinkInfo = result.getHyperlinkInfo();
|
||||
if (!(hyperlinkInfo instanceof FileHyperlinkInfo)) continue;
|
||||
@@ -105,7 +104,7 @@ public class ExceptionExFilterFactory implements ExceptionFilterFactory {
|
||||
}
|
||||
finally {
|
||||
token.finish();
|
||||
visited.put(text, info);
|
||||
visited.put(lineText, info);
|
||||
}
|
||||
}
|
||||
int off = startOffset + lineStartOffset;
|
||||
|
||||
@@ -26,9 +26,9 @@ public class ExceptionFilter implements Filter, DumbAware {
|
||||
myCache = new ExceptionInfoCache(scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result applyFilter(final String line, final int textEndOffset) {
|
||||
ExceptionWorker worker = new ExceptionWorker(myCache);
|
||||
worker.execute(line, textEndOffset);
|
||||
return worker.getResult();
|
||||
return worker.execute(line, textEndOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
@@ -65,7 +66,23 @@ public class ModuleNameLocationComponent {
|
||||
myWizardContext = wizardContext;
|
||||
}
|
||||
|
||||
public void updateDataModel(AbstractModuleBuilder moduleBuilder) {
|
||||
@Nullable
|
||||
public AbstractModuleBuilder getModuleBuilder() {
|
||||
return ((AbstractModuleBuilder)myWizardContext.getProjectBuilder());
|
||||
}
|
||||
|
||||
public boolean validate() throws ConfigurationException {
|
||||
AbstractModuleBuilder builder = getModuleBuilder();
|
||||
if (builder != null && !builder.validateModuleName(getModuleName())) return false;
|
||||
if (!validateModulePaths()) return false;
|
||||
validateExistingModuleName();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void updateDataModel() {
|
||||
AbstractModuleBuilder moduleBuilder = getModuleBuilder();
|
||||
if (moduleBuilder == null) return;
|
||||
|
||||
final String moduleName = getModuleName();
|
||||
moduleBuilder.setName(moduleName);
|
||||
moduleBuilder.setModuleFilePath(
|
||||
@@ -195,8 +212,10 @@ public class ModuleNameLocationComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private void validateExistingModuleName() throws ConfigurationException {
|
||||
Project project = myWizardContext.getProject();
|
||||
if (project == null) return;
|
||||
|
||||
public void validateExistingModuleName(Project project) throws ConfigurationException {
|
||||
final String moduleName = getModuleName();
|
||||
final Module module;
|
||||
final ProjectStructureConfigurable fromConfigurable = ProjectStructureConfigurable.getInstance(project);
|
||||
@@ -211,7 +230,7 @@ public class ModuleNameLocationComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean validateModulePaths() throws ConfigurationException {
|
||||
private boolean validateModulePaths() throws ConfigurationException {
|
||||
final String moduleName = getModuleName();
|
||||
final String moduleFileDirectory = myModuleFileLocation.getText();
|
||||
if (moduleFileDirectory.length() == 0) {
|
||||
|
||||
@@ -135,15 +135,11 @@ public class ProjectSettingsStep extends ModuleWizardStep implements SettingsSte
|
||||
|
||||
@Override
|
||||
public boolean validate() throws ConfigurationException {
|
||||
|
||||
if (myWizardContext.isCreatingNewProject()) {
|
||||
if (!myNamePathComponent.validateNameAndPath(myWizardContext, myFormatPanel.isDefault())) return false;
|
||||
}
|
||||
|
||||
if (!myModuleNameLocationComponent.validateModulePaths()) return false;
|
||||
if (!myWizardContext.isCreatingNewProject()) {
|
||||
myModuleNameLocationComponent.validateExistingModuleName(myWizardContext.getProject());
|
||||
}
|
||||
if (!myModuleNameLocationComponent.validate()) return false;
|
||||
|
||||
if (mySettingsStep != null) {
|
||||
return mySettingsStep.validate();
|
||||
@@ -163,17 +159,15 @@ public class ProjectSettingsStep extends ModuleWizardStep implements SettingsSte
|
||||
|
||||
@Override
|
||||
public void updateDataModel() {
|
||||
|
||||
myWizardContext.setProjectName(myNamePathComponent.getNameValue());
|
||||
myWizardContext.setProjectFileDirectory(myNamePathComponent.getPath());
|
||||
myFormatPanel.updateData(myWizardContext);
|
||||
|
||||
ModuleBuilder moduleBuilder = (ModuleBuilder)myWizardContext.getProjectBuilder();
|
||||
if (moduleBuilder != null) {
|
||||
myModuleNameLocationComponent.updateDataModel(moduleBuilder);
|
||||
if (moduleBuilder instanceof TemplateModuleBuilder) {
|
||||
myWizardContext.setProjectStorageFormat(StorageScheme.DIRECTORY_BASED);
|
||||
}
|
||||
myModuleNameLocationComponent.updateDataModel();
|
||||
|
||||
ProjectBuilder moduleBuilder = myWizardContext.getProjectBuilder();
|
||||
if (moduleBuilder instanceof TemplateModuleBuilder) {
|
||||
myWizardContext.setProjectStorageFormat(StorageScheme.DIRECTORY_BASED);
|
||||
}
|
||||
|
||||
if (mySettingsStep != null) {
|
||||
|
||||
@@ -211,10 +211,7 @@ public class SelectTemplateStep extends ModuleWizardStep implements SettingsStep
|
||||
if (!myNamePathComponent.validateNameAndPath(myWizardContext, myFormatPanel.isDefault())) return false;
|
||||
}
|
||||
|
||||
if (!myModuleNameLocationComponent.validateModulePaths()) return false;
|
||||
if (!myWizardContext.isCreatingNewProject()) {
|
||||
myModuleNameLocationComponent.validateExistingModuleName(myWizardContext.getProject());
|
||||
}
|
||||
if (!myModuleNameLocationComponent.validate()) return false;
|
||||
|
||||
ValidationInfo info = template.validateSettings();
|
||||
if (info != null) {
|
||||
@@ -243,17 +240,15 @@ public class SelectTemplateStep extends ModuleWizardStep implements SettingsStep
|
||||
|
||||
@Override
|
||||
public void updateDataModel() {
|
||||
|
||||
myWizardContext.setProjectBuilder(myModuleBuilder);
|
||||
myWizardContext.setProjectName(myNamePathComponent.getNameValue());
|
||||
myWizardContext.setProjectFileDirectory(myNamePathComponent.getPath());
|
||||
myFormatPanel.updateData(myWizardContext);
|
||||
|
||||
if (myModuleBuilder != null) {
|
||||
myModuleNameLocationComponent.updateDataModel(myModuleBuilder);
|
||||
if (myModuleBuilder instanceof TemplateModuleBuilder) {
|
||||
myWizardContext.setProjectStorageFormat(StorageScheme.DIRECTORY_BASED);
|
||||
}
|
||||
myModuleNameLocationComponent.updateDataModel();
|
||||
|
||||
if (myModuleBuilder instanceof TemplateModuleBuilder) {
|
||||
myWizardContext.setProjectStorageFormat(StorageScheme.DIRECTORY_BASED);
|
||||
}
|
||||
|
||||
if (mySettingsStep != null) {
|
||||
|
||||
+1
-1
@@ -279,7 +279,7 @@ public class HighlightClassUtil {
|
||||
if (directory instanceof PsiDirectory) {
|
||||
String simpleName = aClass.getName();
|
||||
PsiDirectory subDirectory = ((PsiDirectory)directory).findSubdirectory(simpleName);
|
||||
if (subDirectory != null && simpleName.equals(subDirectory.getName())) {
|
||||
if (subDirectory != null && simpleName.equals(subDirectory.getName()) && PsiTreeUtil.findChildOfType(subDirectory, PsiJavaFile.class) != null) {
|
||||
String message = JavaErrorMessages.message("class.clashes.with.package", name);
|
||||
TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(message).create();
|
||||
|
||||
+182
-95
@@ -24,6 +24,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.impl.PsiDiamondTypeUtil;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.siyeh.ig.psiutils.BoolUtils;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import com.siyeh.ig.psiutils.StreamApiUtil;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
@@ -59,6 +60,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
private static final String ANY_MATCH_METHOD = "anyMatch";
|
||||
private static final String NONE_MATCH_METHOD = "noneMatch";
|
||||
private static final String ALL_MATCH_METHOD = "allMatch";
|
||||
private static final String TO_ARRAY_METHOD = "toArray";
|
||||
|
||||
private static final String COUNTING_COLLECTOR = "counting";
|
||||
private static final String TO_LIST_COLLECTOR = "toList";
|
||||
@@ -100,7 +102,10 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
else if (isCallOf(method, CommonClassNames.JAVA_UTIL_OPTIONAL, IS_PRESENT_METHOD, 0)) {
|
||||
handleOptionalIsPresent(methodCall);
|
||||
}
|
||||
else if (isStreamCall(method, ANY_MATCH_METHOD)) {
|
||||
else if (isStreamCall(method, TO_ARRAY_METHOD, false)) {
|
||||
handleToArray(methodCall);
|
||||
}
|
||||
else if (isStreamCall(method, ANY_MATCH_METHOD, true)) {
|
||||
if(isParentNegated(methodCall)) {
|
||||
boolean argNegated = isArgumentLambdaNegated(methodCall);
|
||||
registerMatchFix(methodCall,
|
||||
@@ -109,7 +114,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
argNegated ? ALL_MATCH_METHOD : NONE_MATCH_METHOD));
|
||||
}
|
||||
}
|
||||
else if (isStreamCall(method, NONE_MATCH_METHOD)) {
|
||||
else if (isStreamCall(method, NONE_MATCH_METHOD, true)) {
|
||||
if(isParentNegated(methodCall)) {
|
||||
registerMatchFix(methodCall, new SimplifyMatchNegationFix("!"+psiClass.getName()+".noneMatch(...)", ANY_MATCH_METHOD));
|
||||
}
|
||||
@@ -117,7 +122,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
registerMatchFix(methodCall, new SimplifyMatchNegationFix(psiClass.getName()+".noneMatch(x -> !(...))", ALL_MATCH_METHOD));
|
||||
}
|
||||
}
|
||||
else if (isStreamCall(method, ALL_MATCH_METHOD)) {
|
||||
else if (isStreamCall(method, ALL_MATCH_METHOD, true)) {
|
||||
if(isArgumentLambdaNegated(methodCall)) {
|
||||
boolean parentNegated = isParentNegated(methodCall);
|
||||
registerMatchFix(methodCall,
|
||||
@@ -131,6 +136,20 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
}
|
||||
|
||||
private void handleToArray(PsiMethodCallExpression methodCall) {
|
||||
if(isCollectionStream(getQualifierMethodCall(methodCall))) {
|
||||
PsiArrayType type = getArrayType(methodCall);
|
||||
if(type != null) {
|
||||
PsiElement nameElement = methodCall.getMethodExpression().getReferenceNameElement();
|
||||
LOG.assertTrue(nameElement != null);
|
||||
String replacement = type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT+"[]") ? "" :
|
||||
"new "+type.getCanonicalText().replaceFirst("\\[]", "[0]");
|
||||
holder.registerProblem(nameElement, "Can be replaced with collection.toArray()",
|
||||
new SimplifyCallChainFix(new ReplaceWithToArrayFix(replacement)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void registerMatchFix(PsiMethodCallExpression methodCall, SimplifyMatchNegationFix fix) {
|
||||
PsiElement nameElement = methodCall.getMethodExpression().getReferenceNameElement();
|
||||
if(nameElement != null) {
|
||||
@@ -223,13 +242,6 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
}
|
||||
|
||||
@Contract("null -> false")
|
||||
private boolean isCollectionStream(PsiMethodCallExpression qualifierCall) {
|
||||
if (qualifierCall == null) return false;
|
||||
PsiMethod qualifier = qualifierCall.resolveMethod();
|
||||
return isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTION, STREAM_METHOD, 0);
|
||||
}
|
||||
|
||||
private void handleStreamForEach(PsiMethodCallExpression methodCall, PsiMethod method) {
|
||||
final String name;
|
||||
if (isCallOf(method, CommonClassNames.JAVA_UTIL_STREAM_STREAM, FOR_EACH_METHOD, 1)) {
|
||||
@@ -306,34 +318,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
|
||||
private void handleCollectionStream(PsiMethodCallExpression methodCall) {
|
||||
final PsiMethodCallExpression qualifierCall = getQualifierMethodCall(methodCall);
|
||||
if (qualifierCall == null) return;
|
||||
final PsiMethod qualifier = qualifierCall.resolveMethod();
|
||||
ReplaceCollectionStreamFix fix = null;
|
||||
if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_ARRAYS, AS_LIST_METHOD, 1)) {
|
||||
if (hasSingleArrayArgument(qualifierCall)) {
|
||||
fix = new ArraysAsListSingleArrayFix();
|
||||
}
|
||||
else {
|
||||
fix = new ReplaceWithStreamOfFix("Arrays.asList()");
|
||||
}
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, SINGLETON_LIST_METHOD, 1)) {
|
||||
if (!hasSingleArrayArgument(qualifierCall)) {
|
||||
fix = new ReplaceSingletonWithStreamOfFix("Collections.singletonList()");
|
||||
}
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, SINGLETON_METHOD, 1)) {
|
||||
if (!hasSingleArrayArgument(qualifierCall)) {
|
||||
fix = new ReplaceSingletonWithStreamOfFix("Collections.singleton()");
|
||||
}
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, EMPTY_LIST_METHOD, 0)) {
|
||||
fix = new ReplaceWithStreamEmptyFix(EMPTY_LIST_METHOD);
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, EMPTY_SET_METHOD, 0)) {
|
||||
fix = new ReplaceWithStreamEmptyFix(EMPTY_SET_METHOD);
|
||||
}
|
||||
ReplaceCollectionStreamFix fix = findCollectionStreamFix(methodCall);
|
||||
if (fix != null) {
|
||||
holder.registerProblem(methodCall, null, fix.getMessage(), new SimplifyCallChainFix(fix));
|
||||
}
|
||||
@@ -341,6 +326,102 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ReplaceCollectionStreamFix findCollectionStreamFix(PsiMethodCallExpression methodCall) {
|
||||
PsiMethodCallExpression qualifierCall = getQualifierMethodCall(methodCall);
|
||||
if (qualifierCall == null) return null;
|
||||
PsiMethod qualifier = qualifierCall.resolveMethod();
|
||||
if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_ARRAYS, AS_LIST_METHOD, 1)) {
|
||||
return hasSingleArrayArgument(qualifierCall) ? new ArraysAsListSingleArrayFix() : new ReplaceWithStreamOfFix("Arrays.asList()");
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, SINGLETON_LIST_METHOD, 1)) {
|
||||
if (!hasSingleArrayArgument(qualifierCall)) {
|
||||
return new ReplaceSingletonWithStreamOfFix("Collections.singletonList()");
|
||||
}
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, SINGLETON_METHOD, 1)) {
|
||||
if (!hasSingleArrayArgument(qualifierCall)) {
|
||||
return new ReplaceSingletonWithStreamOfFix("Collections.singleton()");
|
||||
}
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, EMPTY_LIST_METHOD, 0)) {
|
||||
return new ReplaceWithStreamEmptyFix(EMPTY_LIST_METHOD);
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, EMPTY_SET_METHOD, 0)) {
|
||||
return new ReplaceWithStreamEmptyFix(EMPTY_SET_METHOD);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Contract("null -> false")
|
||||
private static boolean isCollectionStream(PsiMethodCallExpression qualifierCall) {
|
||||
if (qualifierCall == null) return false;
|
||||
PsiMethod qualifier = qualifierCall.resolveMethod();
|
||||
return isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTION, STREAM_METHOD, 0);
|
||||
}
|
||||
|
||||
public static PsiElement simplifyCollectionStreamCalls(PsiElement element) {
|
||||
boolean replaced = true;
|
||||
while(replaced) {
|
||||
replaced = false;
|
||||
PsiElement[] streamCalls =
|
||||
PsiTreeUtil.collectElements(element, e -> e instanceof PsiMethodCallExpression && isCollectionStream((PsiMethodCallExpression)e));
|
||||
for (PsiElement streamCall : streamCalls) {
|
||||
if (streamCall.isValid()) {
|
||||
ReplaceCollectionStreamFix fix = findCollectionStreamFix((PsiMethodCallExpression)streamCall);
|
||||
if (fix != null) {
|
||||
PsiElement replacement = fix.simplify((PsiMethodCallExpression)streamCall);
|
||||
if(replacement != null) {
|
||||
replaced = true;
|
||||
if(element == streamCall) {
|
||||
element = replacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiArrayType getArrayType(PsiMethodCallExpression call) {
|
||||
PsiType type = call.getType();
|
||||
if(!(type instanceof PsiArrayType)) return null;
|
||||
PsiArrayType candidate = (PsiArrayType)type;
|
||||
PsiExpression[] args = call.getArgumentList().getExpressions();
|
||||
if(args.length == 0) return candidate;
|
||||
if(args.length != 1) return null;
|
||||
PsiExpression supplier = args[0];
|
||||
if(supplier instanceof PsiMethodReferenceExpression) {
|
||||
// like toArray(String[]::new)
|
||||
PsiMethodReferenceExpression methodRef = (PsiMethodReferenceExpression)supplier;
|
||||
PsiTypeElement qualifierType = methodRef.getQualifierType();
|
||||
if (methodRef.isConstructor() && qualifierType != null && candidate.isAssignableFrom(qualifierType.getType())) {
|
||||
return candidate;
|
||||
}
|
||||
} else if(supplier instanceof PsiLambdaExpression) {
|
||||
// like toArray(size -> new String[size])
|
||||
PsiLambdaExpression lambda = (PsiLambdaExpression)supplier;
|
||||
PsiParameter[] parameters = lambda.getParameterList().getParameters();
|
||||
if(parameters.length != 1) return null;
|
||||
PsiParameter sizeParameter = parameters[0];
|
||||
PsiExpression body = LambdaUtil.extractSingleExpressionFromBody(lambda.getBody());
|
||||
if(body instanceof PsiNewExpression) {
|
||||
PsiNewExpression newExpression = (PsiNewExpression)body;
|
||||
PsiExpression[] dimensions = newExpression.getArrayDimensions();
|
||||
PsiType newExpressionType = newExpression.getType();
|
||||
if (dimensions.length != 0 &&
|
||||
ExpressionUtils.isReferenceTo(dimensions[0], sizeParameter) &&
|
||||
newExpressionType != null &&
|
||||
candidate.isAssignableFrom(newExpressionType)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isCollectionConstructor(PsiMethod ctor) {
|
||||
if(!ctor.getModifierList().hasExplicitModifier(PsiModifier.PUBLIC)) return false;
|
||||
PsiParameterList list = ctor.getParameterList();
|
||||
@@ -452,8 +533,10 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean isStreamCall(@Nullable PsiMethod method, @NotNull String methodName) {
|
||||
if (method == null || !methodName.equals(method.getName()) || method.getParameterList().getParametersCount() != 1) {
|
||||
@Contract("null, _, _ -> false")
|
||||
static boolean isStreamCall(@Nullable PsiMethod method, @NotNull String methodName, boolean checkSingleParameter) {
|
||||
if (method == null || !methodName.equals(method.getName()) ||
|
||||
(checkSingleParameter && method.getParameterList().getParametersCount() != 1)) {
|
||||
return false;
|
||||
}
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
@@ -462,7 +545,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
|
||||
interface CallChainFix {
|
||||
String getName();
|
||||
void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor);
|
||||
void applyFix(@NotNull Project project, PsiElement element);
|
||||
}
|
||||
|
||||
private static class SimplifyCallChainFix implements LocalQuickFix {
|
||||
@@ -488,31 +571,11 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
myFix.applyFix(project, descriptor);
|
||||
myFix.applyFix(project, descriptor.getStartElement());
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class CallChainFixBase implements CallChainFix {
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getStartElement();
|
||||
if (element instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression expression = (PsiMethodCallExpression)element;
|
||||
final PsiExpression forEachMethodQualifier = expression.getMethodExpression().getQualifierExpression();
|
||||
if (forEachMethodQualifier instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression previousExpression = (PsiMethodCallExpression)forEachMethodQualifier;
|
||||
final PsiExpression qualifierExpression = previousExpression.getMethodExpression().getQualifierExpression();
|
||||
replaceMethodCall(expression, previousExpression, qualifierExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void replaceMethodCall(@NotNull PsiMethodCallExpression methodCall,
|
||||
@NotNull PsiMethodCallExpression qualifierCall,
|
||||
@Nullable PsiExpression qualifierExpression);
|
||||
}
|
||||
|
||||
private static abstract class ReplaceCollectionStreamFix extends CallChainFixBase {
|
||||
private static abstract class ReplaceCollectionStreamFix implements CallChainFix {
|
||||
private final String myClassName;
|
||||
private final String myMethodName;
|
||||
private final String myQualifierCall;
|
||||
@@ -542,13 +605,17 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void replaceMethodCall(@NotNull PsiMethodCallExpression methodCall,
|
||||
@NotNull PsiMethodCallExpression qualifierCall,
|
||||
@Nullable PsiExpression qualifierExpression) {
|
||||
methodCall.getArgumentList().replace(qualifierCall.getArgumentList());
|
||||
public void applyFix(@NotNull Project project, PsiElement element) {
|
||||
if (!(element instanceof PsiMethodCallExpression)) return;
|
||||
simplify((PsiMethodCallExpression)element);
|
||||
}
|
||||
|
||||
final Project project = methodCall.getProject();
|
||||
String typeParameter = getTypeParameter(qualifierCall);
|
||||
@Nullable
|
||||
private PsiElement simplify(PsiMethodCallExpression streamCall) {
|
||||
PsiMethodCallExpression collectionCall = getQualifierMethodCall(streamCall);
|
||||
if (collectionCall == null) return null;
|
||||
streamCall.getArgumentList().replace(collectionCall.getArgumentList());
|
||||
String typeParameter = getTypeParameter(collectionCall);
|
||||
String replacement;
|
||||
if (typeParameter != null) {
|
||||
replacement = myClassName + ".<" + typeParameter + ">" + myMethodName;
|
||||
@@ -556,8 +623,9 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
else {
|
||||
replacement = myClassName + "." + myMethodName;
|
||||
}
|
||||
final PsiExpression newMethodExpression = JavaPsiFacade.getElementFactory(project).createExpressionFromText(replacement, methodCall);
|
||||
JavaCodeStyleManager.getInstance(project).shortenClassReferences(methodCall.getMethodExpression().replace(newMethodExpression));
|
||||
Project project = streamCall.getProject();
|
||||
PsiExpression newMethodExpression = JavaPsiFacade.getElementFactory(project).createExpressionFromText(replacement, streamCall);
|
||||
return JavaCodeStyleManager.getInstance(project).shortenClassReferences(streamCall.getMethodExpression().replace(newMethodExpression));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,7 +670,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
}
|
||||
|
||||
static class ReplaceStreamMethodFix extends CallChainFixBase {
|
||||
static class ReplaceStreamMethodFix implements CallChainFix {
|
||||
private final String myStreamMethod;
|
||||
private final String myCollectionMethod;
|
||||
private final boolean myChangeSemantics;
|
||||
@@ -630,19 +698,16 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void replaceMethodCall(@NotNull PsiMethodCallExpression methodCall,
|
||||
@NotNull PsiMethodCallExpression qualifierCall,
|
||||
@Nullable PsiExpression qualifierExpression) {
|
||||
if (qualifierExpression != null) {
|
||||
final PsiElement nameElement = methodCall.getMethodExpression().getReferenceNameElement();
|
||||
if (nameElement != null) {
|
||||
qualifierCall.replace(qualifierExpression);
|
||||
if (!myStreamMethod.equals(myCollectionMethod)) {
|
||||
final Project project = methodCall.getProject();
|
||||
PsiIdentifier collectionMethod = JavaPsiFacade.getElementFactory(project).createIdentifier(myCollectionMethod);
|
||||
nameElement.replace(collectionMethod);
|
||||
}
|
||||
}
|
||||
public void applyFix(@NotNull Project project, PsiElement element) {
|
||||
if (!(element instanceof PsiMethodCallExpression)) return;
|
||||
PsiMethodCallExpression streamMethodCall = (PsiMethodCallExpression)element;
|
||||
PsiMethodCallExpression collectionStreamCall = getQualifierMethodCall(streamMethodCall);
|
||||
if (collectionStreamCall == null) return;
|
||||
PsiExpression collectionExpression = collectionStreamCall.getMethodExpression().getQualifierExpression();
|
||||
if (collectionExpression == null) return;
|
||||
collectionStreamCall.replace(collectionExpression);
|
||||
if (!myStreamMethod.equals(myCollectionMethod)) {
|
||||
streamMethodCall.getMethodExpression().handleElementRename(myCollectionMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -670,8 +735,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement element = descriptor.getStartElement();
|
||||
public void applyFix(@NotNull Project project, PsiElement element) {
|
||||
if (element instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression collectCall = (PsiMethodCallExpression)element;
|
||||
PsiExpression qualifierExpression = collectCall.getMethodExpression().getQualifierExpression();
|
||||
@@ -737,8 +801,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement element = descriptor.getStartElement();
|
||||
public void applyFix(@NotNull Project project, PsiElement element) {
|
||||
if (element instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression isPresentCall = (PsiMethodCallExpression)element;
|
||||
PsiExpression isPresentQualifier = isPresentCall.getMethodExpression().getQualifierExpression();
|
||||
@@ -781,8 +844,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement element = descriptor.getStartElement();
|
||||
public void applyFix(@NotNull Project project, PsiElement element) {
|
||||
if(element instanceof PsiIdentifier) {
|
||||
String from = element.getText();
|
||||
boolean removeParentNegation;
|
||||
@@ -836,8 +898,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement element = descriptor.getStartElement();
|
||||
public void applyFix(@NotNull Project project, PsiElement element) {
|
||||
if(!(element instanceof PsiMethodCallExpression)) return;
|
||||
PsiMethodCallExpression collectCall = (PsiMethodCallExpression)element;
|
||||
PsiType type = collectCall.getType();
|
||||
@@ -875,8 +936,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement element = descriptor.getStartElement();
|
||||
public void applyFix(@NotNull Project project, PsiElement element) {
|
||||
if(!(element instanceof PsiIdentifier)) return;
|
||||
PsiElement parent = element.getParent();
|
||||
if(!(parent instanceof PsiReferenceExpression)) return;
|
||||
@@ -890,4 +950,31 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
((PsiMethodCallExpression)grandParent).getTypeArgumentList().delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReplaceWithToArrayFix implements CallChainFix {
|
||||
private final String myReplacement;
|
||||
|
||||
private ReplaceWithToArrayFix(String replacement) {
|
||||
myReplacement = replacement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Replace 'collection.stream().toArray()' with 'collection.toArray()'";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, PsiElement element) {
|
||||
PsiMethodCallExpression toArrayCall = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
|
||||
if (toArrayCall == null) return;
|
||||
PsiExpression qualifier = toArrayCall.getMethodExpression().getQualifierExpression();
|
||||
if(!(qualifier instanceof PsiMethodCallExpression)) return;
|
||||
PsiMethodCallExpression streamCall = (PsiMethodCallExpression)qualifier;
|
||||
PsiExpression collectionExpression = streamCall.getMethodExpression().getQualifierExpression();
|
||||
if(collectionExpression == null) return;
|
||||
CommentTracker ct = new CommentTracker();
|
||||
PsiElement result = ct.replaceAndRestoreComments(toArrayCall, ct.text(collectionExpression) + ".toArray(" + myReplacement + ")");
|
||||
CodeStyleManager.getInstance(project).reformat(JavaCodeStyleManager.getInstance(project).shortenClassReferences(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user