Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2014-10-28 12:53:05 +03:00
353 changed files with 5035 additions and 2330 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
<component name="libraryTable">
<library name="proxy-vole">
<CLASSES>
<root url="jar://$PROJECT_DIR$/lib/proxy-vole_20120920.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/proxy-vole_20131209.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
@@ -1,20 +1,21 @@
/* The following code was generated by JFlex 1.4.3 on 10/24/14 12:41 PM */
/* The following code was generated by JFlex 1.4.3 on 10/24/14 4:28 PM */
/* It's an automatically generated code. Do not modify it. */
package org.intellij.lang.regexp;
import com.intellij.lexer.FlexLexer;
import com.intellij.psi.tree.IElementType;
import java.util.LinkedList;
import java.util.EnumSet;
import com.intellij.psi.StringEscapesTokenTypes;
import com.intellij.psi.tree.IElementType;
import java.util.ArrayList;
import java.util.EnumSet;
@SuppressWarnings("ALL")
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
* on 10/24/14 12:41 PM from the specification file
* on 10/24/14 4:28 PM from the specification file
* <tt>/Users/bas/Projects/IntelliJ IDEA Ultimate/tools/lexer/../../community/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex</tt>
*/
class _RegExLexer implements FlexLexer {
@@ -404,12 +405,13 @@ class _RegExLexer implements FlexLexer {
/* user code: */
// This adds support for nested states. I'm no JFlex pro, so maybe this is overkill, but it works quite well.
private final LinkedList<Integer> states = new LinkedList();
private final ArrayList<Integer> states = new ArrayList();
// This was an idea to use the regex implementation for XML schema regexes (which use a slightly different syntax)
// as well, but is currently unfinished as it requires to tweak more places than just the lexer.
private boolean xmlSchemaMode;
private int capturingGroupCount = 0;
private boolean allowDanglingMetacharacters;
private boolean allowNestedCharacterClasses;
@@ -433,11 +435,12 @@ class _RegExLexer implements FlexLexer {
}
private void yypushstate(int state) {
states.addFirst(yystate());
states.add(yystate());
yybegin(state);
}
private void yypopstate() {
final int state = states.removeFirst();
final int state = states.remove(states.size() - 1);
yybegin(state);
}
@@ -747,94 +750,85 @@ class _RegExLexer implements FlexLexer {
{ yybegin(YYINITIAL); return RegExpTT.GROUP_END;
}
case 88: break;
case 5:
{ return RegExpTT.GROUP_BEGIN;
}
case 89: break;
case 37:
{ yybegin(YYINITIAL); return RegExpTT.COLON;
}
case 90: break;
case 89: break;
case 6:
{ return RegExpTT.GROUP_END;
}
case 91: break;
case 90: break;
case 25:
{ assert false : yytext();
}
case 92: break;
case 91: break;
case 18:
{ return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CHARACTER;
}
case 93: break;
case 92: break;
case 46:
{ return commentMode ? RegExpTT.CHARACTER : RegExpTT.REDUNDANT_ESCAPE;
}
case 94: break;
case 93: break;
case 23:
{ return RegExpTT.NAME;
}
case 95: break;
case 74:
{ if (allowOctalNoLeadingZero) return RegExpTT.OCT_CHAR;
return yystate() != CLASS2 ? RegExpTT.BACKREF : RegExpTT.ESC_CHARACTER;
}
case 96: break;
case 94: break;
case 29:
{ yypopstate(); return RegExpTT.CLASS_END;
}
case 97: break;
case 95: break;
case 34:
{ yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER;
}
case 98: break;
case 96: break;
case 52:
{ yypushstate(QUOTED); return RegExpTT.QUOTE_BEGIN;
}
case 99: break;
case 97: break;
case 21:
{ return RegExpTT.NUMBER;
}
case 100: break;
case 98: break;
case 4:
{ return RegExpTT.DOT;
}
case 101: break;
case 99: break;
case 72:
{ return RegExpTT.NEG_LOOKBEHIND;
}
case 102: break;
case 100: break;
case 33:
{ yypopstate(); if (allowCategoryShorthand) return RegExpTT.CATEGORY_SHORT_HAND; else yypushback(1);
}
case 103: break;
case 101: break;
case 44:
{ return (allowOctalNoLeadingZero ? RegExpTT.OCT_CHAR : RegExpTT.BAD_OCT_VALUE);
}
case 104: break;
case 102: break;
case 41:
// lookahead expression with fixed base length
zzMarkedPos = zzStartRead + 1;
{ yypushstate(CLASS1);
return RegExpTT.CLASS_BEGIN;
}
case 105: break;
case 103: break;
case 63:
{ return RegExpTT.NEG_LOOKAHEAD;
}
case 106: break;
case 104: break;
case 10:
{ return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CTRL_CHARACTER;
}
case 107: break;
case 105: break;
case 61:
{ return RegExpTT.NON_CAPT_GROUP;
}
case 108: break;
case 106: break;
case 65:
{ yybegin(QUOTED_NAMED_GROUP); return RegExpTT.RUBY_QUOTED_NAMED_GROUP;
}
case 109: break;
case 107: break;
case 66:
// lookahead expression with fixed base length
zzMarkedPos = zzStartRead + 1;
@@ -846,7 +840,7 @@ class _RegExLexer implements FlexLexer {
}
return RegExpTT.CLASS_BEGIN;
}
case 110: break;
case 108: break;
case 28:
{ if (allowNestedCharacterClasses) {
yypushstate(CLASS2);
@@ -854,72 +848,80 @@ class _RegExLexer implements FlexLexer {
}
return RegExpTT.CHARACTER;
}
case 111: break;
case 109: break;
case 19:
{ if (commentMode) { yypushstate(COMMENT); return RegExpTT.COMMENT; } else return RegExpTT.CHARACTER;
}
case 112: break;
case 110: break;
case 51:
{ yypushstate(PROP); return RegExpTT.PROPERTY;
}
case 113: break;
case 111: break;
case 8:
{ yypushstate(CLASS2);
return RegExpTT.CLASS_BEGIN;
}
case 114: break;
case 112: break;
case 71:
{ return RegExpTT.POS_LOOKBEHIND;
}
case 115: break;
case 43:
{ return yystate() != CLASS2 ? RegExpTT.BACKREF : RegExpTT.ESC_CHARACTER;
}
case 116: break;
case 113: break;
case 73:
{ return RegExpTT.HEX_CHAR;
}
case 117: break;
case 114: break;
case 1:
{ handleOptions(); return RegExpTT.OPTIONS_ON;
}
case 118: break;
case 115: break;
case 43:
{ if (yystate() == CLASS2) return RegExpTT.ESC_CHARACTER;
while (yylength() > 2 && Integer.parseInt(yytext().toString().substring(1)) > capturingGroupCount) {
yypushback(1);
}
return RegExpTT.BACKREF;
}
case 116: break;
case 59:
{ return allowNestedCharacterClasses ? RegExpTT.ANDAND : RegExpTT.CHARACTER;
}
case 119: break;
case 117: break;
case 2:
{ yypopstate(); return RegExpTT.COMMENT;
}
case 120: break;
case 118: break;
case 17:
{ return RegExpTT.MINUS;
}
case 121: break;
case 119: break;
case 47:
{ return RegExpTT.ESC_CTRL_CHARACTER;
}
case 122: break;
case 120: break;
case 32:
{ yypopstate(); yypushstate(EMBRACED); return RegExpTT.LBRACE;
}
case 123: break;
case 121: break;
case 13:
{ return RegExpTT.QUEST;
}
case 124: break;
case 122: break;
case 5:
{ capturingGroupCount++; return RegExpTT.GROUP_BEGIN;
}
case 123: break;
case 15:
{ return RegExpTT.PLUS;
}
case 125: break;
case 124: break;
case 67:
{ return RegExpTT.OCT_CHAR;
}
case 126: break;
case 125: break;
case 39:
{ yybegin(YYINITIAL); return RegExpTT.QUOTE;
}
case 127: break;
case 126: break;
case 20:
{ if (allowDanglingMetacharacters) {
yypopstate(); yypushback(1);
@@ -927,15 +929,15 @@ class _RegExLexer implements FlexLexer {
return RegExpTT.BAD_CHARACTER;
}
}
case 128: break;
case 127: break;
case 31:
{ yypopstate(); yypushback(1);
}
case 129: break;
case 128: break;
case 27:
{ yybegin(CLASS1); return RegExpTT.CARET;
}
case 130: break;
case 129: break;
case 57:
// lookahead expression with fixed base length
zzMarkedPos = zzStartRead + 1;
@@ -945,91 +947,100 @@ class _RegExLexer implements FlexLexer {
}
return RegExpTT.CHARACTER;
}
case 131: break;
case 130: break;
case 58:
{ if (!allowNestedCharacterClasses) return RegExpTT.CHARACTER;
return RegExpTT.REDUNDANT_ESCAPE;
}
case 132: break;
case 131: break;
case 38:
{ yybegin(YYINITIAL); return RegExpTT.GT;
}
case 133: break;
case 132: break;
case 69:
{ yybegin(PY_NAMED_GROUP_REF); return RegExpTT.PYTHON_NAMED_GROUP_REF;
}
case 134: break;
case 133: break;
case 16:
{ return RegExpTT.UNION;
}
case 135: break;
case 134: break;
case 3:
{ return RegExpTT.CHARACTER;
}
case 136: break;
case 135: break;
case 64:
{ yybegin(NAMED_GROUP); return RegExpTT.RUBY_NAMED_GROUP;
}
case 137: break;
case 136: break;
case 40:
{ yybegin(OPTIONS); return RegExpTT.SET_OPTIONS;
}
case 138: break;
case 137: break;
case 26:
{ yybegin(CLASS2); return RegExpTT.CHARACTER;
}
case 139: break;
case 138: break;
case 68:
{ if (xmlSchemaMode) { yypushback(1); return RegExpTT.CHAR_CLASS; } else return RegExpTT.CTRL;
}
case 140: break;
case 139: break;
case 30:
{ return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.ESC_CHARACTER;
}
case 141: break;
case 140: break;
case 12:
{ return RegExpTT.DOLLAR;
}
case 142: break;
case 141: break;
case 50:
{ if (xmlSchemaMode) return RegExpTT.CHAR_CLASS; else return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN;
}
case 143: break;
case 142: break;
case 42:
{ return RegExpTT.REDUNDANT_ESCAPE;
}
case 144: break;
case 143: break;
case 55:
{ return (allowHexDigitClass || allowHorizontalWhitespaceClass ? RegExpTT.CHAR_CLASS : StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN);
}
case 145: break;
case 144: break;
case 48:
{ return yystate() != CLASS2 ? RegExpTT.BOUNDARY : RegExpTT.ESC_CHARACTER;
}
case 146: break;
case 145: break;
case 22:
{ yypopstate(); return RegExpTT.RBRACE;
}
case 147: break;
case 146: break;
case 54:
{ return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN;
}
case 148: break;
case 147: break;
case 53:
{ return RegExpTT.BAD_HEX_VALUE;
}
case 149: break;
case 148: break;
case 9:
{ return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN;
}
case 150: break;
case 149: break;
case 11:
{ return RegExpTT.CARET;
}
case 151: break;
case 150: break;
case 45:
{ return RegExpTT.ESC_CHARACTER;
}
case 151: break;
case 74:
{ if (allowOctalNoLeadingZero) return RegExpTT.OCT_CHAR;
if (yystate() == CLASS2) return RegExpTT.ESC_CHARACTER;
while (yylength() > 2 && Integer.parseInt(yytext().toString().substring(1)) > capturingGroupCount) {
yypushback(1);
}
return RegExpTT.BACKREF;
}
case 152: break;
default:
if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
@@ -79,7 +79,12 @@ public final class RegExpLanguageHosts extends ClassExtension<RegExpLanguageHost
return true;
}
final RegExpLanguageHost host = findRegExpHost(regExpChar);
return host != null && host.supportsExtendedHexCharacter(regExpChar);
try {
return host != null && host.supportsExtendedHexCharacter(regExpChar);
} catch (AbstractMethodError e) {
// supportsExtendedHexCharacter not present
return false;
}
}
public boolean supportsNamedGroupSyntax(@Nullable final RegExpGroup group) {
@@ -2,10 +2,11 @@
package org.intellij.lang.regexp;
import com.intellij.lexer.FlexLexer;
import com.intellij.psi.tree.IElementType;
import java.util.LinkedList;
import java.util.EnumSet;
import com.intellij.psi.StringEscapesTokenTypes;
import com.intellij.psi.tree.IElementType;
import java.util.ArrayList;
import java.util.EnumSet;
@SuppressWarnings("ALL")
%%
@@ -20,12 +21,13 @@ import com.intellij.psi.StringEscapesTokenTypes;
%{
// This adds support for nested states. I'm no JFlex pro, so maybe this is overkill, but it works quite well.
private final LinkedList<Integer> states = new LinkedList();
private final ArrayList<Integer> states = new ArrayList();
// This was an idea to use the regex implementation for XML schema regexes (which use a slightly different syntax)
// as well, but is currently unfinished as it requires to tweak more places than just the lexer.
private boolean xmlSchemaMode;
private int capturingGroupCount = 0;
private boolean allowDanglingMetacharacters;
private boolean allowNestedCharacterClasses;
@@ -49,11 +51,12 @@ import com.intellij.psi.StringEscapesTokenTypes;
}
private void yypushstate(int state) {
states.addFirst(yystate());
states.add(yystate());
yybegin(state);
}
private void yypopstate() {
final int state = states.removeFirst();
final int state = states.remove(states.size() - 1);
yybegin(state);
}
@@ -144,15 +147,21 @@ HEX_CHAR=[0-9a-fA-F]
subexpressions exist at that point in the regular expression, otherwise the
parser will drop digits until the number is smaller or equal to the existing
number of groups or it is one digit."
So, for 100% compatibility, backrefs > 9 should be resolved by the parser, but
I'm not sure if it's worth the effort - at least not atm.
*/
{ESCAPE} [0-7]{3} { if (allowOctalNoLeadingZero) return RegExpTT.OCT_CHAR;
return yystate() != CLASS2 ? RegExpTT.BACKREF : RegExpTT.ESC_CHARACTER;
if (yystate() == CLASS2) return RegExpTT.ESC_CHARACTER;
while (yylength() > 2 && Integer.parseInt(yytext().toString().substring(1)) > capturingGroupCount) {
yypushback(1);
}
return RegExpTT.BACKREF;
}
{ESCAPE} {DIGITS} { return yystate() != CLASS2 ? RegExpTT.BACKREF : RegExpTT.ESC_CHARACTER; }
{ESCAPE} {DIGITS} { if (yystate() == CLASS2) return RegExpTT.ESC_CHARACTER;
while (yylength() > 2 && Integer.parseInt(yytext().toString().substring(1)) > capturingGroupCount) {
yypushback(1);
}
return RegExpTT.BACKREF;
}
{ESCAPE} "-" { return RegExpTT.ESC_CHARACTER; }
{ESCAPE} {META} { return RegExpTT.ESC_CHARACTER; }
@@ -256,7 +265,7 @@ HEX_CHAR=[0-9a-fA-F]
<YYINITIAL> {
{LPAREN} { return RegExpTT.GROUP_BEGIN; }
{LPAREN} { capturingGroupCount++; return RegExpTT.GROUP_BEGIN; }
{RPAREN} { return RegExpTT.GROUP_END; }
"|" { return RegExpTT.UNION; }
+8
View File
@@ -730,6 +730,14 @@
<pattern>([ab]+)=\1</pattern>
<expected>OK</expected>
</test>
<test>
<pattern>(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)\105</pattern>
<expected>OK</expected>
</test>
<test>
<pattern>(.)\11</pattern>
<expected>OK</expected>
</test>
<test verify="false">
<pattern>([ab]+)=\2</pattern>
<expected>ERR</expected>
+1 -1
View File
@@ -262,7 +262,7 @@ libraryLicense(name: "Snappy-Java", libraryName: "Snappy-Java", version: "0.3",
libraryLicense(name: "Cucumber-Java", libraryName: "cucumber-java", version: "1.0.14", license: "MIT License", url: "https://github.com/cucumber/cucumber-jvm/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html")
libraryLicense(name: "Cucumber-JVM", libraryName: "cucumber-jvm", version: "1.0.14", license: "MIT License", url: "https://github.com/cucumber/cucumber-jvm/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html")
libraryLicense(name: "Cucumber-Groovy", libraryName: "cucumber-groovy", version: "1.0.14", license: "MIT License", url: "https://github.com/cucumber/cucumber-jvm/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html")
libraryLicense(name: "proxy-vole", libraryName: "proxy-vole", version: "20120920", license: "New BSD License", url: "http://code.google.com/p/proxy-vole/", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause")
libraryLicense(name: "proxy-vole", libraryName: "proxy-vole", version: "20131209", license: "New BSD License", url: "http://code.google.com/p/proxy-vole/", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause")
libraryLicense(name: "Rhino JavaScript Engine", libraryName: "rhino-js-1_7R4", version: "1.7R4", license: "MPL 1.1", url: "http://www.mozilla.org/rhino/", licenseUrl: "http://www.mozilla.org/MPL/MPL-1.1.html")
libraryLicense(name: "asm-4.0-all", libraryName: "asm-4.0-all", version: "4.0", attachedTo: "ByteCodeViewer", license: "BSD", url: "http://asm.objectweb.org/", licenseUrl: "http://asm.objectweb.org/license.html")
libraryLicense(name: "jsr305", libraryName: "jsr305", version: "snapshot", license: "BSD", url: "http://code.google.com/p/jsr-305/", licenseUrl: "http://code.google.com/p/jsr-305/source/browse/trunk/ri/LICENSE")
+20
View File
@@ -691,6 +691,26 @@ private String submapToXml(Map properties, List keys) {
return buff.toString()
}
private List<File> getChildren(File file) {
if (!file.isDirectory()) return []
return file.listFiles().sort { File f -> f.name.toLowerCase() }
}
binding.setVariable("getCustomJDK", { File customJdkDir ->
getChildren(customJdkDir).each {
if (it.getName().endsWith(".tar.gz")) {
def customJdkFileName = it.getAbsolutePath().substring(0, it.getAbsolutePath().length() - 3)
if (new File(customJdkFileName).exists()){ ant.delete(file: customJdkFileName) }
if (new File("${home}/build/jdk/custom_jdk_${buildNumber}.tar").exists()){
ant.delete(file: "${home}/build/jdk/custom_jdk_${buildNumber}.tar")
}
ant.gunzip(src: it.getAbsolutePath())
projectBuilder.info("customJdkFileName: " + customJdkFileName)
ant.copy(file: customJdkFileName, tofile: "${home}/build/jdk/custom_jdk_${buildNumber}.tar")
}
}
})
binding.setVariable("buildWinZip", { String zipPath, List paths ->
projectBuilder.stage(".win.zip")
@@ -73,7 +73,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jps.api.CmdlineProtoUtil;
import org.jetbrains.jps.api.CmdlineRemoteProto;
import org.jetbrains.jps.api.RequestFuture;
import org.jetbrains.jps.api.TaskFuture;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import javax.swing.*;
@@ -138,7 +138,7 @@ public class CompileDriver {
return;
}
try {
final RequestFuture future = compileInExternalProcess(compileContext, true);
final TaskFuture future = compileInExternalProcess(compileContext, true);
if (future != null) {
while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) {
if (indicator.isCanceled()) {
@@ -194,7 +194,7 @@ public class CompileDriver {
}
@Nullable
private RequestFuture compileInExternalProcess(final @NotNull CompileContextImpl compileContext, final boolean onlyCheckUpToDate)
private TaskFuture compileInExternalProcess(final @NotNull CompileContextImpl compileContext, final boolean onlyCheckUpToDate)
throws Exception {
final CompileScope scope = compileContext.getCompileScope();
final Collection<String> paths = CompileScopeUtil.fetchFiles(compileContext);
@@ -400,7 +400,7 @@ public class CompileDriver {
return;
}
final RequestFuture future = compileInExternalProcess(compileContext, false);
final TaskFuture future = compileInExternalProcess(compileContext, false);
if (future != null) {
while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) {
if (indicator.isCanceled()) {
@@ -646,7 +646,6 @@ public class CompileDriver {
final Module[] scopeModules = scope.getAffectedModules();
final List<String> modulesWithoutOutputPathSpecified = new ArrayList<String>();
final List<String> modulesWithoutJdkAssigned = new ArrayList<String>();
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
final CompilerManager compilerManager = CompilerManager.getInstance(myProject);
for (final Module module : scopeModules) {
if (!compilerManager.isValidationEnabled(module)) {
@@ -58,10 +58,7 @@ import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.ShutDownTracker;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
@@ -112,8 +109,7 @@ import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.*;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope;
@@ -152,8 +148,10 @@ public class BuildManager implements ApplicationComponent{
private final File mySystemDirectory;
private final ProjectManager myProjectManager;
private final Map<RequestFuture, Project> myAutomakeFutures = Collections.synchronizedMap(new HashMap<RequestFuture, Project>());
private final Map<TaskFuture, Project> myAutomakeFutures = Collections.synchronizedMap(new HashMap<TaskFuture, Project>());
private final Map<String, RequestFuture> myBuildsInProgress = Collections.synchronizedMap(new HashMap<String, RequestFuture>());
private final Map<String, Future<Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler>>> myPreloadedBuilds =
Collections.synchronizedMap(new HashMap<String, Future<Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler>>>());
private final BuildProcessClasspathManager myClasspathManager = new BuildProcessClasspathManager();
private final SequentialTaskExecutor myRequestsProcessor = new SequentialTaskExecutor(PooledThreadExecutor.INSTANCE);
private final Map<String, ProjectData> myProjectDataMap = Collections.synchronizedMap(new HashMap<String, ProjectData>());
@@ -385,6 +383,8 @@ public class BuildManager implements ApplicationComponent{
}
public void clearState(Project project) {
cancelPreloadedBuilds(project);
final String projectPath = getProjectPath(project);
synchronized (myProjectDataMap) {
final ProjectData data = myProjectDataMap.get(projectPath);
@@ -447,7 +447,7 @@ public class BuildManager implements ApplicationComponent{
}
final List<TargetTypeBuildScope> scopes = CmdlineProtoUtil.createAllModulesScopes(false);
final AutoMakeMessageHandler handler = new AutoMakeMessageHandler(project);
final RequestFuture future = scheduleBuild(
final TaskFuture future = scheduleBuild(
project, false, true, false, scopes, Collections.<String>emptyList(), Collections.<String, String>emptyMap(), handler
);
if (future != null) {
@@ -526,12 +526,12 @@ public class BuildManager implements ApplicationComponent{
return false;
}
public Collection<RequestFuture> cancelAutoMakeTasks(Project project) {
final Collection<RequestFuture> futures = new SmartList<RequestFuture>();
public Collection<TaskFuture> cancelAutoMakeTasks(Project project) {
final Collection<TaskFuture> futures = new SmartList<TaskFuture>();
synchronized (myAutomakeFutures) {
for (Map.Entry<RequestFuture, Project> entry : myAutomakeFutures.entrySet()) {
for (Map.Entry<TaskFuture, Project> entry : myAutomakeFutures.entrySet()) {
if (entry.getValue().equals(project)) {
final RequestFuture future = entry.getKey();
final TaskFuture future = entry.getKey();
future.cancel(false);
futures.add(future);
}
@@ -540,211 +540,261 @@ public class BuildManager implements ApplicationComponent{
return futures;
}
private void cancelPreloadedBuilds(Project project) {
final String projectPath = getProjectPath(project);
runCommand(new Runnable() {
@Override
public void run() {
Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler> pair = takePreloadedProcess(projectPath);
if (pair != null) {
final RequestFuture<PreloadedProcessMessageHandler> future = pair.first;
myMessageDispatcher.cancelSession(future.getRequestID());
// waiting for preloaded process from project's task queue guarantees no build is started for this project
// until this one gracefully exits and closes all its storages
getProjectData(projectPath).taskQueue.submit(new Runnable() {
@Override
public void run() {
future.waitFor();
}
});
}
}
});
}
@Nullable
public RequestFuture scheduleBuild(
private Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler> takePreloadedProcess(String projectPath) {
Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler> result;
final Future<Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler>> preloadProgress = myPreloadedBuilds.remove(projectPath);
try {
result = preloadProgress != null ? preloadProgress.get() : null;
}
catch (Throwable e) {
LOG.info(e);
result = null;
}
return result;
}
@Nullable
public TaskFuture scheduleBuild(
final Project project, final boolean isRebuild, final boolean isMake,
final boolean onlyCheckUpToDate, final List<TargetTypeBuildScope> scopes,
final Collection<String> paths,
final Map<String, String> userData, final DefaultMessageHandler messageHandler) {
final String projectPath = getProjectPath(project);
final UUID sessionId = UUID.randomUUID();
final boolean isAutomake = messageHandler instanceof AutoMakeMessageHandler;
final BuilderMessageHandler handler = new MessageHandlerWrapper(messageHandler) {
@Override
public void buildStarted(UUID sessionId) {
super.buildStarted(sessionId);
try {
ApplicationManager.getApplication().getMessageBus().syncPublisher(BuildManagerListener.TOPIC).buildStarted(project, sessionId, isAutomake);
}
catch (Throwable e) {
LOG.error(e);
}
}
@Override
public void sessionTerminated(UUID sessionId) {
try {
super.sessionTerminated(sessionId);
}
finally {
try {
ApplicationManager.getApplication().getMessageBus().syncPublisher(BuildManagerListener.TOPIC).buildFinished(project, sessionId, isAutomake);
}
catch (Throwable e) {
LOG.error(e);
}
}
}
};
// ensure server is listening
if (myListenPort < 0) {
try {
synchronized (this) {
if (myListenPort < 0) {
myListenPort = startListening();
}
}
}
catch (Exception e) {
handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), null));
handler.sessionTerminated(sessionId);
return null;
}
final BuilderMessageHandler handler = new NotifyingMessageHandler(project, messageHandler, messageHandler instanceof AutoMakeMessageHandler);
try {
ensureListening();
}
catch (Exception e) {
final UUID sessionId = UUID.randomUUID(); // the actual session did not start, use random UUID
handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), null));
handler.sessionTerminated(sessionId);
return null;
}
try {
final RequestFuture<BuilderMessageHandler> future = new RequestFuture<BuilderMessageHandler>(handler, sessionId, new RequestFuture.CancelAction<BuilderMessageHandler>() {
@Override
public void cancel(RequestFuture<BuilderMessageHandler> future) throws Exception {
myMessageDispatcher.cancelSession(future.getRequestID());
final DelegateFuture<BuilderMessageHandler> _future = new DelegateFuture<BuilderMessageHandler>();
// by using the same queue that processes events we ensure that
// the build will be aware of all events that have happened before this request
runCommand(new Runnable() {
@Override
public void run() {
final Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler> preloaded = takePreloadedProcess(projectPath);
final RequestFuture<PreloadedProcessMessageHandler> preloadedFuture = preloaded != null? preloaded.first : null;
final boolean usingPreloadedProcess = preloadedFuture != null;
final UUID sessionId;
if (usingPreloadedProcess) {
LOG.info("Using preloaded build process to compile " + projectPath);
sessionId = preloadedFuture.getRequestID();
preloadedFuture.getMessageHandler().setDelegateHandler(handler);
}
else {
sessionId = UUID.randomUUID();
}
});
// by using the same queue that processes events we ensure that
// the build will be aware of all events that have happened before this request
runCommand(new Runnable() {
@Override
public void run() {
if (future.isCancelled() || project.isDisposed()) {
handler.sessionTerminated(sessionId);
future.setDone();
return;
}
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals =
CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.newBuilder()
.setGlobalOptionsPath(PathManager.getOptionsPath())
.build();
CmdlineRemoteProto.Message.ControllerMessage.FSEvent currentFSChanges;
final SequentialTaskExecutor projectTaskQueue;
synchronized (myProjectDataMap) {
ProjectData data = myProjectDataMap.get(projectPath);
if (data == null) {
data = new ProjectData(new SequentialTaskExecutor(PooledThreadExecutor.INSTANCE));
myProjectDataMap.put(projectPath, data);
}
if (isRebuild) {
data.dropChanges();
}
if (IS_UNIT_TEST_MODE) {
LOG.info("Scheduling build for " +
projectPath +
"; CHANGED: " +
new HashSet<String>(convertToStringPaths(data.myChanged)) +
"; DELETED: " +
new HashSet<String>(convertToStringPaths(data.myDeleted)));
}
currentFSChanges = data.getAndResetRescanFlag() ? null : data.createNextEvent();
projectTaskQueue = data.taskQueue;
final RequestFuture<? extends BuilderMessageHandler> future = usingPreloadedProcess? preloadedFuture : new RequestFuture<BuilderMessageHandler>(handler, sessionId, new RequestFuture.CancelAction<BuilderMessageHandler>() {
@Override
public void cancel(RequestFuture<BuilderMessageHandler> future) throws Exception {
myMessageDispatcher.cancelSession(future.getRequestID());
}
});
_future.setDelegate(future);
final CmdlineRemoteProto.Message.ControllerMessage params;
if (!usingPreloadedProcess && (future.isCancelled() || project.isDisposed())) {
// in case of preloaded process the process was already running, so the handler will be notified upon process termination
handler.sessionTerminated(sessionId);
((BasicFuture)future).setDone();
return;
}
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals =
CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.newBuilder().setGlobalOptionsPath(PathManager.getOptionsPath()).build();
CmdlineRemoteProto.Message.ControllerMessage.FSEvent currentFSChanges;
final SequentialTaskExecutor projectTaskQueue;
synchronized (myProjectDataMap) {
final ProjectData data = getProjectData(projectPath);
if (isRebuild) {
params = CmdlineProtoUtil.createBuildRequest(projectPath, scopes, Collections.<String>emptyList(), userData, globals, null);
data.dropChanges();
}
else if (onlyCheckUpToDate) {
params = CmdlineProtoUtil.createUpToDateCheckRequest(projectPath, scopes, paths, userData, globals, currentFSChanges);
}
else {
params = CmdlineProtoUtil.createBuildRequest(projectPath, scopes, isMake ? Collections.<String>emptyList() : paths,
userData, globals, currentFSChanges);
if (IS_UNIT_TEST_MODE) {
LOG.info("Scheduling build for " +
projectPath +
"; CHANGED: " +
new HashSet<String>(convertToStringPaths(data.myChanged)) +
"; DELETED: " +
new HashSet<String>(convertToStringPaths(data.myDeleted)));
}
currentFSChanges = data.getAndResetRescanFlag() ? null : data.createNextEvent();
projectTaskQueue = data.taskQueue;
}
myMessageDispatcher.registerBuildMessageHandler(sessionId, new MessageHandlerWrapper(handler) {
final CmdlineRemoteProto.Message.ControllerMessage params;
if (isRebuild) {
params = CmdlineProtoUtil.createBuildRequest(projectPath, scopes, Collections.<String>emptyList(), userData, globals, null);
}
else if (onlyCheckUpToDate) {
params = CmdlineProtoUtil.createUpToDateCheckRequest(projectPath, scopes, paths, userData, globals, currentFSChanges);
}
else {
params = CmdlineProtoUtil.createBuildRequest(projectPath, scopes, isMake ? Collections.<String>emptyList() : paths, userData, globals, currentFSChanges);
}
if (!usingPreloadedProcess) {
myMessageDispatcher.registerBuildMessageHandler(future, params);
}
try {
projectTaskQueue.submit(new Runnable() {
@Override
public void sessionTerminated(UUID sessionId) {
public void run() {
Throwable execFailure = null;
try {
super.sessionTerminated(sessionId);
}
finally {
future.setDone();
}
}
}, params);
try {
projectTaskQueue.submit(new Runnable() {
@Override
public void run() {
Throwable execFailure = null;
try {
if (project.isDisposed()) {
if (project.isDisposed()) {
if (usingPreloadedProcess) {
future.cancel(true);
}
else {
return;
}
myBuildsInProgress.put(projectPath, future);
final OSProcessHandler processHandler = launchBuildProcess(project, myListenPort, sessionId);
final StringBuilder stdErrOutput = new StringBuilder();
}
myBuildsInProgress.put(projectPath, future);
final OSProcessHandler processHandler;
final StringBuilder errorsOnLaunch = new StringBuilder();
if (usingPreloadedProcess) {
final boolean paramsSent = myMessageDispatcher.sendBuildParameters(future.getRequestID(), params);
if (!paramsSent) {
myMessageDispatcher.cancelSession(future.getRequestID());
}
processHandler = preloaded.second;
}
else {
processHandler = launchBuildProcess(project, myListenPort, sessionId, false);
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
// re-translate builder's output to idea.log
final String text = event.getText();
if (!StringUtil.isEmptyOrSpaces(text)) {
LOG.info("BUILDER_PROCESS [" + outputType.toString() + "]: " + text.trim());
if (stdErrOutput.length() < 1024 && ProcessOutputTypes.STDERR.equals(outputType)) {
stdErrOutput.append(text);
if (ProcessOutputTypes.STDERR.equals(outputType)) {
if (errorsOnLaunch.length() < 1024) {
final String text = event.getText();
if (!StringUtil.isEmptyOrSpaces(text)) {
errorsOnLaunch.append(text);
}
}
}
}
});
processHandler.startNotify();
final boolean terminated = processHandler.waitFor();
if (terminated) {
final int exitValue = processHandler.getProcess().exitValue();
if (exitValue != 0) {
final StringBuilder msg = new StringBuilder();
msg.append("Abnormal build process termination: ");
if (stdErrOutput.length() > 0) {
msg.append("\n").append(stdErrOutput);
}
else {
msg.append("unknown error");
}
handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(msg.toString(), null));
}
final boolean terminated = processHandler.waitFor();
if (terminated) {
final int exitValue = processHandler.getProcess().exitValue();
if (exitValue != 0) {
final StringBuilder msg = new StringBuilder();
msg.append("Abnormal build process termination: ");
if (errorsOnLaunch.length() > 0) {
msg.append("\n").append(errorsOnLaunch);
}
}
else {
handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure("Disconnected from build process", null));
else {
msg.append("unknown error");
}
handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(msg.toString(), null));
}
}
catch (Throwable e) {
execFailure = e;
}
finally {
myBuildsInProgress.remove(projectPath);
if (myMessageDispatcher.getAssociatedChannel(sessionId) == null) {
// either the connection has never been established (process not started or execution failed), or no messages were sent from the launched process.
// in this case the session cannot be unregistered by the message dispatcher
final BuilderMessageHandler unregistered = myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
if (unregistered != null) {
if (execFailure != null) {
unregistered.handleFailure(sessionId, CmdlineProtoUtil.createFailure(execFailure.getMessage(), execFailure));
}
unregistered.sessionTerminated(sessionId);
}
}
else {
handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure("Disconnected from build process", null));
}
}
});
}
catch (Throwable e) {
final BuilderMessageHandler unregistered = myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
if (unregistered != null) {
unregistered.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e));
unregistered.sessionTerminated(sessionId);
catch (Throwable e) {
execFailure = e;
}
finally {
myBuildsInProgress.remove(projectPath);
if (myMessageDispatcher.getAssociatedChannel(sessionId) == null) {
// either the connection has never been established (process not started or execution failed), or no messages were sent from the launched process.
// in this case the session cannot be unregistered by the message dispatcher
final BuilderMessageHandler unregistered = myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
if (unregistered != null) {
if (execFailure != null) {
unregistered.handleFailure(sessionId, CmdlineProtoUtil.createFailure(execFailure.getMessage(), execFailure));
}
unregistered.sessionTerminated(sessionId);
}
}
if (Registry.is("compiler.process.preload") && !project.isDisposed()) {
runCommand(new Runnable() {
public void run() {
try {
final Future<Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler>> preloadResult = launchPreloadedBuildProcess(project, projectTaskQueue);
myPreloadedBuilds.put(projectPath, preloadResult);
}
catch (Exception e) {
LOG.info("Error pre-loading build process for project " + projectPath, e);
}
}
});
}
}
}
});
}
catch (Throwable e) {
final BuilderMessageHandler unregistered = myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
if (unregistered != null) {
unregistered.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e));
unregistered.sessionTerminated(sessionId);
}
}
});
}
});
return future;
}
catch (Throwable e) {
handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e));
handler.sessionTerminated(sessionId);
}
return _future;
}
return null;
@NotNull
private ProjectData getProjectData(String projectPath) {
synchronized (myProjectDataMap) {
ProjectData data = myProjectDataMap.get(projectPath);
if (data == null) {
data = new ProjectData(new SequentialTaskExecutor(PooledThreadExecutor.INSTANCE));
myProjectDataMap.put(projectPath, data);
}
return data;
}
}
private void ensureListening() throws Exception {
if (myListenPort < 0) {
synchronized (this) {
if (myListenPort < 0) {
myListenPort = startListening();
}
}
}
}
@Override
@@ -762,7 +812,45 @@ public class BuildManager implements ApplicationComponent{
return "com.intellij.compiler.server.BuildManager";
}
private OSProcessHandler launchBuildProcess(Project project, final int port, final UUID sessionId) throws ExecutionException {
private Future<Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler>> launchPreloadedBuildProcess(final Project project, SequentialTaskExecutor projectTaskQueue) throws Exception {
ensureListening();
// launching build process from projectTaskQueue ensures that no other build process for this project is currently running
return projectTaskQueue.submit(new Callable<Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler>>() {
public Pair<RequestFuture<PreloadedProcessMessageHandler>, OSProcessHandler> call() throws Exception {
final RequestFuture<PreloadedProcessMessageHandler> future = new RequestFuture<PreloadedProcessMessageHandler>(new PreloadedProcessMessageHandler(project), UUID.randomUUID(), new RequestFuture.CancelAction<PreloadedProcessMessageHandler>() {
@Override
public void cancel(RequestFuture<PreloadedProcessMessageHandler> future) throws Exception {
myMessageDispatcher.cancelSession(future.getRequestID());
}
});
try {
myMessageDispatcher.registerBuildMessageHandler(future, null);
final OSProcessHandler processHandler = launchBuildProcess(project, myListenPort, future.getRequestID(), true);
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
if (ProcessOutputTypes.STDERR.equals(outputType)) {
final String text = event.getText();
if (!StringUtil.isEmptyOrSpaces(text)) {
LOG.info("PRELOADED_BUILD_PROCESS: " + text);
}
}
}
});
processHandler.startNotify();
return Pair.create(future, processHandler);
}
catch (ExecutionException e) {
myMessageDispatcher.unregisterBuildMessageHandler(future.getRequestID());
throw e;
}
}
});
}
private OSProcessHandler launchBuildProcess(Project project, final int port, final UUID sessionId, boolean requestProjectPreload) throws ExecutionException {
final String compilerPath;
final String vmExecutablePath;
JavaSdkVersion sdkVersion = null;
@@ -863,6 +951,11 @@ public class BuildManager implements ApplicationComponent{
}
cmdLine.addParameter("-Djdt.compiler.useSingleThread=true"); // always run eclipse compiler in single-threaded mode
if (requestProjectPreload) {
cmdLine.addParameter("-Dpreload.project.path=" + FileUtil.toCanonicalPath(getProjectPath(project)));
cmdLine.addParameter("-Dpreload.config.path=" + FileUtil.toCanonicalPath(PathManager.getOptionsPath()));
}
final String shouldGenerateIndex = System.getProperty(GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION);
if (shouldGenerateIndex != null) {
cmdLine.addParameter("-D"+ GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION +"=" + shouldGenerateIndex);
@@ -961,12 +1054,24 @@ public class BuildManager implements ApplicationComponent{
final Process process = cmdLine.createProcess();
return new OSProcessHandler(process, null, mySystemCharset) {
final OSProcessHandler processHandler = new OSProcessHandler(process, null, mySystemCharset) {
@Override
protected boolean shouldDestroyProcessRecursively() {
return true;
}
};
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
// re-translate builder's output to idea.log
final String text = event.getText();
if (!StringUtil.isEmptyOrSpaces(text)) {
LOG.info("BUILDER_PROCESS [" + outputType.toString() + "]: " + text.trim());
}
}
});
return processHandler;
}
public File getBuildSystemDirectory() {
@@ -1086,6 +1191,50 @@ public class BuildManager implements ApplicationComponent{
}
}
private static class NotifyingMessageHandler extends DelegatingMessageHandler {
private final Project myProject;
private final BuilderMessageHandler myDelegateHandler;
private boolean myIsAutomake;
public NotifyingMessageHandler(@NotNull Project project, @NotNull BuilderMessageHandler delegateHandler, final boolean isAutomake) {
myProject = project;
myDelegateHandler = delegateHandler;
myIsAutomake = isAutomake;
}
@Override
protected BuilderMessageHandler getDelegateHandler() {
return myDelegateHandler;
}
@Override
public void buildStarted(UUID sessionId) {
super.buildStarted(sessionId);
try {
ApplicationManager
.getApplication().getMessageBus().syncPublisher(BuildManagerListener.TOPIC).buildStarted(myProject, sessionId, myIsAutomake);
}
catch (Throwable e) {
LOG.error(e);
}
}
@Override
public void sessionTerminated(UUID sessionId) {
try {
super.sessionTerminated(sessionId);
}
finally {
try {
ApplicationManager.getApplication().getMessageBus().syncPublisher(BuildManagerListener.TOPIC).buildFinished(myProject, sessionId, myIsAutomake);
}
catch (Throwable e) {
LOG.error(e);
}
}
}
}
private class ProjectWatcher extends ProjectManagerAdapter {
private final Map<Project, MessageBusConnection> myConnections = new HashMap<Project, MessageBusConnection>();
@@ -1169,7 +1318,8 @@ public class BuildManager implements ApplicationComponent{
@Override
public void projectClosing(Project project) {
for (RequestFuture future : cancelAutoMakeTasks(project)) {
cancelPreloadedBuilds(project);
for (TaskFuture future : cancelAutoMakeTasks(project)) {
future.waitFor(500, TimeUnit.MILLISECONDS);
}
}
@@ -1185,13 +1335,14 @@ public class BuildManager implements ApplicationComponent{
}
private static class ProjectData {
@NotNull
final SequentialTaskExecutor taskQueue;
private final Set<InternedPath> myChanged = new THashSet<InternedPath>();
private final Set<InternedPath> myDeleted = new THashSet<InternedPath>();
private long myNextEventOrdinal = 0L;
private boolean myNeedRescan = true;
private ProjectData(SequentialTaskExecutor taskQueue) {
private ProjectData(@NotNull SequentialTaskExecutor taskQueue) {
this.taskQueue = taskQueue;
}
@@ -1328,5 +1479,88 @@ public class BuildManager implements ApplicationComponent{
return "/";
}
}
private static final class DelegateFuture<T> implements TaskFuture<T> {
@Nullable
private TaskFuture<? extends T> myDelegate;
private Boolean myRequestedCancelState = null;
@NotNull
public synchronized TaskFuture<? extends T> getDelegate() {
TaskFuture<? extends T> delegate = myDelegate;
while (delegate == null) {
try {
wait();
}
catch (InterruptedException ignored) {
}
delegate = myDelegate;
}
return delegate;
}
public synchronized boolean setDelegate(@NotNull TaskFuture<? extends T> delegate) {
if (myDelegate == null) {
try {
myDelegate = delegate;
if (myRequestedCancelState != null) {
myDelegate.cancel(myRequestedCancelState);
}
}
finally {
notifyAll();
}
return true;
}
return false;
}
public synchronized boolean cancel(boolean mayInterruptIfRunning) {
final TaskFuture<? extends T> delegate = myDelegate;
if (delegate == null) {
myRequestedCancelState = mayInterruptIfRunning;
return true;
}
return delegate.cancel(mayInterruptIfRunning);
}
public void waitFor() {
getDelegate().waitFor();
}
public boolean waitFor(long timeout, TimeUnit unit) {
return getDelegate().waitFor(timeout, unit);
}
public boolean isCancelled() {
final TaskFuture<? extends T> delegate;
synchronized (this) {
delegate = myDelegate;
if (delegate == null) {
return myRequestedCancelState != null;
}
}
return delegate.isCancelled();
}
public boolean isDone() {
final TaskFuture<? extends T> delegate;
synchronized (this) {
delegate = myDelegate;
if (delegate == null) {
return false;
}
}
return delegate.isDone();
}
public T get() throws InterruptedException, java.util.concurrent.ExecutionException {
return getDelegate().get();
}
public T get(long timeout, TimeUnit unit) throws InterruptedException, java.util.concurrent.ExecutionException, TimeoutException {
return getDelegate().get(timeout, unit);
}
}
}
@@ -21,10 +21,12 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.io.SimpleChannelInboundHandlerAdapter;
import org.jetbrains.jps.api.CmdlineProtoUtil;
import org.jetbrains.jps.api.CmdlineRemoteProto;
import org.jetbrains.jps.api.RequestFuture;
import java.util.Map;
import java.util.Set;
@@ -41,19 +43,34 @@ class BuildMessageDispatcher extends SimpleChannelInboundHandlerAdapter<CmdlineR
private static final AttributeKey<SessionData> SESSION_DATA = AttributeKey.valueOf("BuildMessageDispatcher.sessionData");
private final Map<UUID, SessionData> myMessageHandlers = new ConcurrentHashMap<UUID, SessionData>(16, 0.75f, 1);
private final Map<UUID, SessionData> mySessionDescriptors = new ConcurrentHashMap<UUID, SessionData>(16, 0.75f, 1);
private final Set<UUID> myCanceledSessions = new ConcurrentHashSet<UUID>();
public void registerBuildMessageHandler(UUID sessionId,
BuilderMessageHandler handler,
CmdlineRemoteProto.Message.ControllerMessage params) {
myMessageHandlers.put(sessionId, new SessionData(sessionId, handler, params));
public void registerBuildMessageHandler(@NotNull final RequestFuture<? extends BuilderMessageHandler> future, @Nullable CmdlineRemoteProto.Message.ControllerMessage params) {
final BuilderMessageHandler wrappedHandler = new DelegatingMessageHandler() {
@Override
protected BuilderMessageHandler getDelegateHandler() {
return future.getMessageHandler();
}
@Override
public void sessionTerminated(UUID sessionId) {
try {
super.sessionTerminated(sessionId);
}
finally {
future.setDone();
}
}
};
final UUID sessionId = future.getRequestID();
mySessionDescriptors.put(sessionId, new SessionData(sessionId, wrappedHandler, params));
}
@Nullable
public BuilderMessageHandler unregisterBuildMessageHandler(UUID sessionId) {
myCanceledSessions.remove(sessionId);
final SessionData data = myMessageHandlers.remove(sessionId);
final SessionData data = mySessionDescriptors.remove(sessionId);
return data != null? data.handler : null;
}
@@ -74,11 +91,36 @@ class BuildMessageDispatcher extends SimpleChannelInboundHandlerAdapter<CmdlineR
@Nullable
public Channel getAssociatedChannel(final UUID sessionId) {
final SessionData data = myMessageHandlers.get(sessionId);
final SessionData data = mySessionDescriptors.get(sessionId);
return data != null? data.channel : null;
}
public boolean sendBuildParameters(@NotNull final UUID preloadedSessionId, @NotNull CmdlineRemoteProto.Message.ControllerMessage params) {
boolean succeeded = false;
final SessionData sessionData = mySessionDescriptors.get(preloadedSessionId);
if (sessionData != null) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (sessionData) {
if (sessionData.state == SessionData.State.WAITING_PARAMS) {
sessionData.state = SessionData.State.RUNNING;
final Channel channel = sessionData.channel;
if (channel != null && channel.isActive()) {
sessionData.handler.buildStarted(preloadedSessionId);
channel.writeAndFlush(CmdlineProtoUtil.toMessage(preloadedSessionId, params));
succeeded = true;
}
}
else {
if (sessionData.state == SessionData.State.INITIAL) {
sessionData.params = params;
succeeded = true;
}
}
}
}
return succeeded;
}
@Override
protected void messageReceived(ChannelHandlerContext context, CmdlineRemoteProto.Message message) throws Exception {
SessionData sessionData = context.attr(SESSION_DATA).get();
@@ -89,7 +131,7 @@ class BuildMessageDispatcher extends SimpleChannelInboundHandlerAdapter<CmdlineR
final CmdlineRemoteProto.Message.UUID id = message.getSessionId();
sessionId = new UUID(id.getMostSigBits(), id.getLeastSigBits());
sessionData = myMessageHandlers.get(sessionId);
sessionData = mySessionDescriptors.get(sessionId);
if (sessionData != null) {
sessionData.channel = context.channel();
context.attr(SESSION_DATA).set(sessionData);
@@ -119,14 +161,25 @@ class BuildMessageDispatcher extends SimpleChannelInboundHandlerAdapter<CmdlineR
final CmdlineRemoteProto.Message.BuilderMessage builderMessage = message.getBuilderMessage();
final CmdlineRemoteProto.Message.BuilderMessage.Type msgType = builderMessage.getType();
if (msgType == CmdlineRemoteProto.Message.BuilderMessage.Type.PARAM_REQUEST) {
final CmdlineRemoteProto.Message.ControllerMessage params = sessionData.params;
if (params != null) {
handler.buildStarted(sessionId);
sessionData.params = null;
context.writeAndFlush(CmdlineProtoUtil.toMessage(sessionId, params));
}
else {
cancelSession(sessionId);
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (sessionData) {
final CmdlineRemoteProto.Message.ControllerMessage params = sessionData.params;
if (params != null) {
sessionData.state = SessionData.State.RUNNING;
handler.buildStarted(sessionId);
sessionData.params = null;
context.writeAndFlush(CmdlineProtoUtil.toMessage(sessionId, params));
}
else {
if (sessionData.state == SessionData.State.INITIAL) {
sessionData.state = SessionData.State.WAITING_PARAMS;
}
else {
// this message is expected to be sent only once.
// To be on the safe side, cancel the session
cancelSession(sessionId);
}
}
}
}
else {
@@ -165,12 +218,19 @@ class BuildMessageDispatcher extends SimpleChannelInboundHandlerAdapter<CmdlineR
}
private static final class SessionData {
enum State {
INITIAL, WAITING_PARAMS, RUNNING
}
@NotNull
final UUID sessionId;
@NotNull
final BuilderMessageHandler handler;
volatile CmdlineRemoteProto.Message.ControllerMessage params;
volatile Channel channel;
State state = State.INITIAL;
private SessionData(UUID sessionId, BuilderMessageHandler handler, CmdlineRemoteProto.Message.ControllerMessage params) {
private SessionData(@NotNull UUID sessionId, @NotNull BuilderMessageHandler handler, CmdlineRemoteProto.Message.ControllerMessage params) {
this.sessionId = sessionId;
this.handler = handler;
this.params = params;
@@ -25,6 +25,24 @@ import java.util.UUID;
* Date: 4/25/12
*/
public interface BuilderMessageHandler {
BuilderMessageHandler DEAF = new BuilderMessageHandler() {
@Override
public void buildStarted(UUID sessionId) {
}
@Override
public void handleBuildMessage(Channel channel, UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage msg) {
}
@Override
public void handleFailure(UUID sessionId, CmdlineRemoteProto.Message.Failure failure) {
}
@Override
public void sessionTerminated(UUID sessionId) {
}
};
void buildStarted(UUID sessionId);
void handleBuildMessage(Channel channel, UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage msg);
@@ -9,30 +9,27 @@ import java.util.UUID;
* @author Eugene Zhuravlev
* Date: 7/3/13
*/
class MessageHandlerWrapper implements BuilderMessageHandler {
private final BuilderMessageHandler myHandler;
abstract class DelegatingMessageHandler implements BuilderMessageHandler {
public MessageHandlerWrapper(BuilderMessageHandler handler) {
myHandler = handler;
}
protected abstract BuilderMessageHandler getDelegateHandler();
@Override
public void buildStarted(UUID sessionId) {
myHandler.buildStarted(sessionId);
getDelegateHandler().buildStarted(sessionId);
}
@Override
public void handleBuildMessage(Channel channel, UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage msg) {
myHandler.handleBuildMessage(channel, sessionId, msg);
getDelegateHandler().handleBuildMessage(channel, sessionId, msg);
}
@Override
public void handleFailure(UUID sessionId, CmdlineRemoteProto.Message.Failure failure) {
myHandler.handleFailure(sessionId, failure);
getDelegateHandler().handleFailure(sessionId, failure);
}
@Override
public void sessionTerminated(UUID sessionId) {
myHandler.sessionTerminated(sessionId);
getDelegateHandler().sessionTerminated(sessionId);
}
}
@@ -0,0 +1,48 @@
/*
* Copyright 2000-2014 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.server;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
/**
* @author Eugene Zhuravlev
* Date: 20-Oct-14
*/
class PreloadedProcessMessageHandler extends DelegatingMessageHandler {
@NotNull
private final Project myProject;
private volatile BuilderMessageHandler myDelegateHandler;
public PreloadedProcessMessageHandler(@NotNull Project project) {
myProject = project;
}
@NotNull
public Project getProject() {
return myProject;
}
@Override
protected BuilderMessageHandler getDelegateHandler() {
final BuilderMessageHandler delegate = myDelegateHandler;
return delegate != null? delegate : BuilderMessageHandler.DEAF;
}
public void setDelegateHandler(BuilderMessageHandler delegateHandler) {
myDelegateHandler = delegateHandler;
}
}
@@ -50,7 +50,7 @@ public class JavaReferringObjectsValue extends JavaValue {
}
public JavaReferringObjectsValue(@NotNull JavaValue javaValue, boolean isField) {
super(null, javaValue.getDescriptor(), javaValue.getEvaluationContext(), null, false);
super(null, javaValue.getDescriptor(), javaValue.getEvaluationContext(), javaValue.getNodeManager(), false);
myIsField = isField;
}
@@ -84,7 +84,7 @@ public class JavaReferringObjectsValue extends JavaValue {
return reference;
}
};
children.add(new JavaReferringObjectsValue(null, descriptor, getEvaluationContext(), null, true));
children.add(new JavaReferringObjectsValue(null, descriptor, getEvaluationContext(), getNodeManager(), true));
i++;
}
else {
@@ -109,7 +109,7 @@ public class JavaReferringObjectsValue extends JavaValue {
return null;
}
};
children.add("Referrer " + i++, new JavaReferringObjectsValue(null, descriptor, getEvaluationContext(), null, false));
children.add("Referrer " + i++, new JavaReferringObjectsValue(null, descriptor, getEvaluationContext(), getNodeManager(), false));
}
}
@@ -168,4 +168,10 @@ public class JavaReferringObjectsValue extends JavaValue {
}
return null;
}
@Nullable
@Override
public XValueModifier getModifier() {
return null;
}
}
@@ -70,6 +70,7 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
private final EvaluationContextImpl myEvaluationContext;
private final NodeManagerImpl myNodeManager;
private final boolean myContextSet;
private final DebuggerManagerThreadImpl myDebuggerManagerThread;
protected JavaValue(JavaValue parent,
@NotNull ValueDescriptorImpl valueDescriptor,
@@ -82,6 +83,7 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
myEvaluationContext = evaluationContext;
myNodeManager = nodeManager;
myContextSet = contextSet;
myDebuggerManagerThread = evaluationContext.getDebugProcess().getManagerThread();
}
static JavaValue create(JavaValue parent,
@@ -113,6 +115,10 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
return myEvaluationContext;
}
public NodeManagerImpl getNodeManager() {
return myNodeManager;
}
@Override
public void computePresentation(@NotNull final XValueNode node, @NotNull XValuePlace place) {
final SuspendContextImpl suspendContext = myEvaluationContext.getSuspendContext();
@@ -349,7 +355,11 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
}
boolean scheduleCommand(SuspendContextCommandImpl command) {
return scheduleCommand(myEvaluationContext, null, command);
if (myEvaluationContext.getSuspendContext().isResumed()) {
return false;
}
myDebuggerManagerThread.schedule(command);
return true;
}
protected static boolean scheduleCommand(EvaluationContextImpl evaluationContext,
@@ -486,6 +496,7 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
@Nullable
@Override
public XReferrersProvider getReferrersProvider() {
if (myEvaluationContext.getSuspendContext().isResumed()) return null;
return new XReferrersProvider() {
@Override
public XValue getReferringObjectsValue() {
@@ -497,16 +508,15 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
@Nullable
@Override
public XInstanceEvaluator getInstanceEvaluator() {
final DebugProcessImpl process = myEvaluationContext.getDebugProcess();
return new XInstanceEvaluator() {
@Override
public void evaluate(@NotNull final XDebuggerEvaluator.XEvaluationCallback callback, @NotNull final XStackFrame frame) {
process.getManagerThread().schedule(new DebuggerCommandImpl() {
myDebuggerManagerThread.schedule(new DebuggerCommandImpl() {
@Override
protected void action() throws Exception {
ValueDescriptorImpl inspectDescriptor = myValueDescriptor;
if (myValueDescriptor instanceof WatchItemDescriptor) {
inspectDescriptor = (ValueDescriptorImpl) ((WatchItemDescriptor) myValueDescriptor).getModifier().getInspectItem(getProject());
inspectDescriptor = (ValueDescriptorImpl)((WatchItemDescriptor)myValueDescriptor).getModifier().getInspectItem(getProject());
}
EvaluationContextImpl evaluationContext = ((JavaStackFrame)frame).getFrameDebuggerContext().createEvaluationContext();
if (evaluationContext != null) {
@@ -192,7 +192,7 @@ public class ArrayRenderer extends NodeRendererImpl{
if(!myForced && END_INDEX < array.length() - 1) {
//children.add(nodeManager.createMessageNode(new MessageDescriptor(MORE_ELEMENTS, MessageDescriptor.SPECIAL)));
builder.setRemaining(array.length()-END_INDEX);
builder.setRemaining(array.length()-1-END_INDEX);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,14 +15,5 @@
*/
package com.intellij.ide.actions;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.ex.ProjectManagerEx;
public class TemplateProjectStructureAction extends AnAction implements DumbAware {
@Override
public void actionPerformed(final AnActionEvent e) {
ShowStructureSettingsAction.showDialog(ProjectManagerEx.getInstanceEx().getDefaultProject());
}
public class TemplateProjectStructureAction extends ShowStructureSettingsAction {
}
@@ -260,7 +260,7 @@ public class HighlightControlFlowUtil {
}
else {
PsiElement scope = variable instanceof PsiField
? variable.getContainingFile()
? ((PsiField)variable).getContainingClass()
: variable.getParent() != null ? variable.getParent().getParent() : null;
if (scope instanceof PsiCodeBlock && scope.getParent() instanceof PsiSwitchStatement) {
scope = PsiTreeUtil.getParentOfType(scope, PsiCodeBlock.class);
@@ -17,6 +17,7 @@ package com.intellij.codeInspection;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.ChangeContextUtil;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil;
import com.intellij.codeInsight.intention.HighPriorityAction;
@@ -208,6 +209,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
if (element instanceof PsiNewExpression) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass();
LOG.assertTrue(anonymousClass != null);
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInspection;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
@@ -115,6 +116,7 @@ public class AnonymousCanBeMethodReferenceInspection extends BaseJavaBatchLocalI
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
if (element instanceof PsiNewExpression) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass();
if (anonymousClass == null) return;
final PsiMethod[] methods = anonymousClass.getMethods();
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInspection;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.openapi.diagnostic.Logger;
@@ -94,7 +95,9 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaBatchLocalInspec
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiDiamondTypeUtil.replaceExplicitWithDiamond(descriptor.getPsiElement());
final PsiElement element = descriptor.getPsiElement();
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
PsiDiamondTypeUtil.replaceExplicitWithDiamond(element);
}
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInspection;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
@@ -390,6 +391,7 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class);
if (lambdaExpression == null) return;
final PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType();
@@ -16,6 +16,7 @@
package com.intellij.codeInspection;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
@@ -133,6 +134,7 @@ public class PossibleHeapPollutionVarargsInspection extends BaseJavaBatchLocalIn
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement psiElement = descriptor.getPsiElement();
if (psiElement instanceof PsiIdentifier) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(psiElement)) return;
final PsiMethod psiMethod = (PsiMethod)psiElement.getParent();
psiMethod.getModifierList().setModifierProperty(PsiModifier.FINAL, true);
new AddAnnotationPsiFix("java.lang.SafeVarargs", psiMethod, PsiNameValuePair.EMPTY_ARRAY).applyFix(project, descriptor);
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInspection;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.openapi.diagnostic.Logger;
@@ -158,6 +159,7 @@ public class RedundantLambdaCodeBlockInspection extends BaseJavaBatchLocalInspec
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
if (element != null) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class);
if (lambdaExpression != null) {
final PsiElement body = lambdaExpression.getBody();
@@ -470,7 +470,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
? InspectionsBundle.message("dataflow.message.return.null.from.notnullable", presentableNullable)
: InspectionsBundle.message("dataflow.message.return.nullable.from.notnullable", presentableNullable);
final LocalQuickFix[] fixes =
PsiTreeUtil.skipParentsOfType(expr, PsiCodeBlock.class, PsiReturnStatement.class) instanceof PsiLambdaExpression
PsiTreeUtil.getParentOfType(expr, PsiMethod.class, PsiLambdaExpression.class) instanceof PsiLambdaExpression
? LocalQuickFix.EMPTY_ARRAY
: new LocalQuickFix[]{ new AnnotateMethodFix(defaultNullable, ArrayUtil.toStringArray(manager.getNotNulls())) {
@Override
@@ -168,6 +168,10 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett
String groupName = ApplicationBundle.message("wrapping.fields.annotation");
consumer.showCustomOption(JavaCodeStyleSettings.class, "DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION", "Do not wrap after single annotation", groupName);
}
else if (settingsType == SettingsType.BLANK_LINES_SETTINGS) {
consumer.showAllStandardOptions();
consumer.showCustomOption(JavaCodeStyleSettings.class, "BLANK_LINES_AROUND_INITIALIZER", ApplicationBundle.message("editbox.blanklines.around.initializer"), CodeStyleSettingsCustomizable.BLANK_LINES);
}
else {
consumer.showAllStandardOptions();
}
@@ -35,4 +35,6 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings {
public int ANNOTATION_PARAMETER_WRAP = CommonCodeStyleSettings.DO_NOT_WRAP;
public boolean ALIGN_MULTILINE_ANNOTATION_PARAMETERS = false;
public int BLANK_LINES_AROUND_INITIALIZER = 1;
}
@@ -341,31 +341,11 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor {
@Override
public void visitClassInitializer(PsiClassInitializer initializer) {
JavaElementArrangementEntry entry = createNewEntry(initializer, initializer.getTextRange(), FIELD, null, true);
JavaElementArrangementEntry entry = createNewEntry(initializer, initializer.getTextRange(), INIT_BLOCK, null, true);
if (entry == null) {
return;
}
PsiElement classLBrace = null;
PsiClass clazz = initializer.getContainingClass();
if (clazz != null) {
classLBrace = clazz.getLBrace();
}
for (PsiElement e = initializer.getPrevSibling(); e != null; e = e.getPrevSibling()) {
JavaElementArrangementEntry prevEntry;
if (e == classLBrace) {
prevEntry = myEntries.get(clazz);
}
else {
prevEntry = myEntries.get(e);
}
if (prevEntry != null) {
entry.addDependency(prevEntry);
}
if (!(e instanceof PsiWhiteSpace)) {
break;
}
}
parseModifiers(initializer.getModifierList(), entry);
}
@NotNull
@@ -27,6 +27,7 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.codeStyle.arrangement.engine.ArrangementEngine;
import com.intellij.psi.codeStyle.arrangement.group.ArrangementGroupingRule;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher;
@@ -36,6 +37,7 @@ import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchConditio
import com.intellij.psi.codeStyle.arrangement.model.ArrangementCompositeMatchCondition;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition;
import com.intellij.psi.codeStyle.arrangement.std.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -62,7 +64,7 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
// Type
@NotNull private static final Set<ArrangementSettingsToken> SUPPORTED_TYPES =
ContainerUtilRt.newLinkedHashSet(
FIELD, CONSTRUCTOR, METHOD, CLASS, INTERFACE, ENUM, GETTER, SETTER, OVERRIDDEN
FIELD, INIT_BLOCK, CONSTRUCTOR, METHOD, CLASS, INTERFACE, ENUM, GETTER, SETTER, OVERRIDDEN
);
// Modifier
@NotNull private static final Set<ArrangementSettingsToken> SUPPORTED_MODIFIERS =
@@ -79,6 +81,9 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
@NotNull private static final Collection<Set<ArrangementSettingsToken>> MUTEXES =
ContainerUtilRt.newArrayList();
private static final Set<ArrangementSettingsToken> TYPES_WITH_DISABLED_ORDER = ContainerUtil.newHashSet();
private static final Set<ArrangementSettingsToken> TYPES_WITH_DISABLED_NAME_MATCH = ContainerUtil.newHashSet();
static {
Set<ArrangementSettingsToken> visibilityModifiers = ContainerUtilRt.newHashSet(PUBLIC, PROTECTED, PACKAGE_PRIVATE, PRIVATE);
MUTEXES.add(visibilityModifiers);
@@ -96,6 +101,11 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
MODIFIERS_BY_TYPE.put(GETTER, ContainerUtilRt.<ArrangementSettingsToken>newHashSet());
MODIFIERS_BY_TYPE.put(SETTER, ContainerUtilRt.<ArrangementSettingsToken>newHashSet());
MODIFIERS_BY_TYPE.put(OVERRIDDEN, ContainerUtilRt.<ArrangementSettingsToken>newHashSet());
MODIFIERS_BY_TYPE.put(INIT_BLOCK, ContainerUtilRt.newHashSet(STATIC));
TYPES_WITH_DISABLED_ORDER.add(INIT_BLOCK);
TYPES_WITH_DISABLED_NAME_MATCH.add(INIT_BLOCK);
}
private static final Map<ArrangementSettingsToken, List<ArrangementSettingsToken>> GROUPING_RULES = ContainerUtilRt.newLinkedHashMap();
@@ -129,6 +139,8 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
for (ArrangementSettingsToken modifier : visibility) {
and(matchRules, FIELD, STATIC, modifier);
}
and(matchRules, INIT_BLOCK, STATIC);
for (ArrangementSettingsToken modifier : visibility) {
and(matchRules, FIELD, FINAL, modifier);
}
@@ -136,6 +148,7 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
and(matchRules, FIELD, modifier);
}
and(matchRules, FIELD);
and(matchRules, INIT_BLOCK);
and(matchRules, CONSTRUCTOR);
and(matchRules, METHOD, STATIC);
and(matchRules, METHOD);
@@ -304,10 +317,14 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
}
CommonCodeStyleSettings commonSettings = settings.getCommonSettings(JavaLanguage.INSTANCE);
JavaCodeStyleSettings javaSettings = settings.getCustomSettings(JavaCodeStyleSettings.class);
if (FIELD.equals(target.getType())) {
if (parent != null && parent.getType() == INTERFACE) {
return commonSettings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE;
}
else if (INIT_BLOCK.equals(previous.getType())) {
return javaSettings.BLANK_LINES_AROUND_INITIALIZER;
}
else {
return commonSettings.BLANK_LINES_AROUND_FIELD;
}
@@ -323,6 +340,9 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
else if (CLASS.equals(target.getType())) {
return commonSettings.BLANK_LINES_AROUND_CLASS;
}
else if (INIT_BLOCK.equals(target.getType())) {
return javaSettings.BLANK_LINES_AROUND_INITIALIZER;
}
else {
return -1;
}
@@ -363,9 +383,10 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
@Override
public boolean isEnabled(@NotNull ArrangementSettingsToken token, @Nullable ArrangementMatchCondition current) {
if (SUPPORTED_TYPES.contains(token) || SUPPORTED_ORDERS.contains(token) || StdArrangementTokens.Regexp.NAME.equals(token)) {
if (SUPPORTED_TYPES.contains(token)) {
return true;
}
ArrangementSettingsToken type = null;
if (current != null) {
type = ArrangementUtil.parseType(current);
@@ -373,6 +394,15 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
if (type == null) {
type = NO_TYPE;
}
if (SUPPORTED_ORDERS.contains(token)) {
return !TYPES_WITH_DISABLED_ORDER.contains(type);
}
if (StdArrangementTokens.Regexp.NAME.equals(token)) {
return !TYPES_WITH_DISABLED_NAME_MATCH.contains(type);
}
Set<ArrangementSettingsToken> modifiers = MODIFIERS_BY_TYPE.get(type);
return modifiers != null && modifiers.contains(token);
}
@@ -39,6 +39,7 @@ import com.intellij.psi.impl.source.tree.java.ClassElement;
import com.intellij.psi.jsp.JspElementType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -90,6 +91,8 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
private final JavaWrapManager myWrapManager;
private final AlignmentInColumnsHelper myAlignmentInColumnsHelper;
private Map<IElementType, Wrap> myPreferredWraps;
private AbstractJavaBlock myParentBlock;
protected AbstractJavaBlock(@NotNull final ASTNode node,
final Wrap wrap,
@@ -505,12 +508,9 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS);
}
else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.PARAMETER_LIST) {
// There is a possible case that particular annotated method definition is too long. We may wrap either after annotation
// or after opening lbrace then. Our strategy is to wrap after annotation whenever possible.
Wrap wrap = Wrap.createWrap(getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false);
child = processParenthesisBlock(result, child,
WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
mySettings.ALIGN_MULTILINE_PARAMETERS);
Wrap wrapToUse = getMethodParametersWrap();
WrappingStrategy wrapStrategy = WrappingStrategy.createDoNotWrapCommaStrategy(wrapToUse);
child = processParenthesisBlock(result, child, wrapStrategy, mySettings.ALIGN_MULTILINE_PARAMETERS);
}
else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.RESOURCE_LIST) {
Wrap wrap = Wrap.createWrap(getWrapType(mySettings.RESOURCE_LIST_WRAP), false);
@@ -572,6 +572,25 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
return child;
}
@NotNull
private Wrap getMethodParametersWrap() {
Wrap preferredWrap = getModifierListWrap();
if (preferredWrap == null) {
return Wrap.createWrap(getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false);
} else {
return Wrap.createChildWrap(preferredWrap, getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false);
}
}
@Nullable
private Wrap getModifierListWrap() {
AbstractJavaBlock parentBlock = getParentBlock();
if (parentBlock != null) {
return parentBlock.getReservedWrap(JavaElementType.MODIFIER_LIST);
}
return null;
}
private ASTNode processField(@NotNull final List<Block> result,
ASTNode child,
@NotNull final AlignmentStrategy alignmentStrategy,
@@ -1135,7 +1154,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
@Nullable
@Override
public Wrap getReservedWrap(IElementType elementType) {
return null;
return myPreferredWraps != null ? myPreferredWraps.get(elementType) : null;
}
/**
@@ -1150,7 +1169,11 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
* @param reservedWrap reserved wrap instance
* @param operationType target operation type to associate with the given wrap instance
*/
protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
public void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
if (myPreferredWraps == null) {
myPreferredWraps = ContainerUtil.newHashMap();
}
myPreferredWraps.put(operationType, reservedWrap);
}
@Nullable
@@ -1262,6 +1285,14 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
return null;
}
public AbstractJavaBlock getParentBlock() {
return myParentBlock;
}
public void setParentBlock(@NotNull AbstractJavaBlock parentBlock) {
myParentBlock = parentBlock;
}
/**
* Allows to answer if special 'variable declaration alignment' strategy should be used for the given node.
* I.e. given node is supposed to be parent node of sub-nodes that should be aligned 'by-columns'.
@@ -61,8 +61,13 @@ public class BlockContainingJavaBlock extends AbstractJavaBlock{
buildChildren(result, childAlignment, childWrap);
return result;
for (Block block : result) {
if (block instanceof AbstractJavaBlock) {
((AbstractJavaBlock)block).setParentBlock(this);
}
}
return result;
}
private void buildChildren(final ArrayList<Block> result, final Alignment childAlignment, final Wrap childWrap) {
@@ -425,13 +425,8 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (myRole1 == ChildRole.FIELD) {
int lines = Math.max(getLinesAroundField(), getLinesAroundMethod()) + 1;
// IJ has been keeping initialization block which starts at the same line as a field for a while.
// However, it's not convenient for a situation when particular code is created via PSI - it's easier to not bothering
// with whitespace elements when inserting, say, new initialization blocks. That's why we don't enforce new line
// only during explicit reformatting ('Reformat' action).
//int minLineFeeds = FormatterUtil.isFormatterCalledExplicitly() ? 0 : 1;
myResult = Spacing.createSpacing(0, mySettings.SPACE_BEFORE_CLASS_LBRACE ? 1 : 0, 1, true, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE, lines);
int blankLines = myJavaSettings.BLANK_LINES_AROUND_INITIALIZER + 1;
myResult = Spacing.createSpacing(0, mySettings.SPACE_BEFORE_CLASS_LBRACE ? 1 : 0, blankLines, true, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
}
else if (myRole1 == ChildRole.CLASS) {
setAroundClassSpacing();
@@ -450,7 +445,7 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor {
setAroundClassSpacing();
}
else {
final int blankLines = getLinesAroundMethod() + 1;
final int blankLines = myJavaSettings.BLANK_LINES_AROUND_INITIALIZER + 1;
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
}
@@ -127,7 +127,7 @@ public class SimpleJavaBlock extends AbstractJavaBlock {
}
@Override
protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
public void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
myReservedWrap.put(operationType, reservedWrap);
}
@@ -19,8 +19,8 @@ import com.intellij.formatting.ASTBlock;
import com.intellij.formatting.Block;
import com.intellij.formatting.Wrap;
import com.intellij.lang.ASTNode;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.formatter.java.AbstractJavaBlock;
import com.intellij.psi.formatter.java.wrap.impl.JavaChildBlockWrapFactory;
import com.intellij.psi.formatter.java.wrap.impl.JavaChildWrapArranger;
import org.jetbrains.annotations.Nullable;
@@ -79,7 +79,7 @@ public class JavaWrapManager {
*/
@Nullable
public Wrap arrangeChildWrap(ASTNode child, ASTNode parent, CommonCodeStyleSettings settings, Wrap suggestedWrap,
ReservedWrapsProvider reservedWrapsProvider)
AbstractJavaBlock reservedWrapsProvider)
{
return myChildArranger.arrange(child, parent, settings, suggestedWrap, reservedWrapsProvider);
}
@@ -22,6 +22,7 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.formatter.java.AbstractJavaBlock;
import com.intellij.psi.formatter.java.JavaFormatterUtil;
import com.intellij.psi.formatter.java.wrap.JavaWrapManager;
import com.intellij.psi.formatter.java.wrap.ReservedWrapsProvider;
@@ -70,7 +71,7 @@ public class JavaChildWrapArranger {
ASTNode parent,
CommonCodeStyleSettings settings,
Wrap suggestedWrap,
ReservedWrapsProvider reservedWrapsProvider) {
AbstractJavaBlock reservedWrapsProvider) {
final JavaCodeStyleSettings javaSettings = settings.getRootSettings().getCustomSettings(JavaCodeStyleSettings.class);
ASTNode directParent = child.getTreeParent();
int role = ((CompositeElement)directParent).getChildRole(child);
@@ -188,8 +189,9 @@ public class JavaChildWrapArranger {
if (javaSettings.DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION && isFieldModifierListWithSingleAnnotation(parent)) {
return Wrap.createWrap(WrapType.NONE, false);
}
return Wrap.createWrap(getWrapType(getAnnotationWrapType(parent.getTreeParent(), child, settings)), true);
Wrap wrap = Wrap.createWrap(getWrapType(getAnnotationWrapType(parent.getTreeParent(), child, settings)), true);
putPreferredWrapInParentBlock(reservedWrapsProvider, wrap);
return wrap;
}
return null;
@@ -263,6 +265,13 @@ public class JavaChildWrapArranger {
return suggestedWrap;
}
private static void putPreferredWrapInParentBlock(@NotNull AbstractJavaBlock block, @NotNull Wrap preferredWrap) {
AbstractJavaBlock parentBlock = block.getParentBlock();
if (parentBlock != null) {
parentBlock.setReservedWrap(preferredWrap, JavaElementType.MODIFIER_LIST);
}
}
private static boolean isFieldModifierListWithSingleAnnotation(@NotNull ASTNode elem) {
ASTNode parent = elem.getTreeParent();
if (parent != null && parent.getElementType() == JavaElementType.FIELD) {
@@ -92,12 +92,28 @@ public class ExtractLightMethodObjectHandler {
final TextRange range = originalContext.getTextRange();
final PsiElement originalAnchor =
CodeInsightUtil.findElementInRange(copy, range.getStartOffset(), range.getEndOffset(), originalContext.getClass());
//todo before this or super, not found etc
final PsiElement anchor = RefactoringUtil.getParentStatement(originalAnchor, false);
if (anchor == null) {
final PsiClass containingClass = PsiTreeUtil.getParentOfType(originalAnchor, PsiClass.class);
if (containingClass == null) {
return null;
}
final PsiElement container = anchor.getParent();
PsiElement anchor = RefactoringUtil.getParentStatement(originalAnchor, false);
if (anchor == null) {
if (PsiTreeUtil.getParentOfType(originalAnchor, PsiCodeBlock.class) != null) {
anchor = originalAnchor;
}
}
final PsiElement container;
if (anchor == null) {
container = ((PsiClassInitializer)containingClass.add(elementFactory.createClassInitializer())).getBody();
anchor = container.getLastChild();
}
else {
container = anchor.getParent();
}
final PsiElement firstElementCopy = container.addRangeBefore(elements[0], elements[elements.length - 1], anchor);
final PsiElement[] elementsCopy = CodeInsightUtil.findStatementsInRange(copy,
firstElementCopy.getTextRange().getStartOffset(),
@@ -870,16 +870,22 @@ public class RefactoringUtil {
JavaCodeStyleManager.getInstance(declaration.getProject()).shortenClassReferences(declaration);
if (loopBodyCopy != null) codeBlock.add(loopBodyCopy);
} else if (container instanceof PsiLambdaExpression) {
final PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)container;
final PsiElement lambdaExpressionBody = lambdaExpression.getBody();
LOG.assertTrue(lambdaExpressionBody != null);
PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)container;
final PsiElement invalidBody = lambdaExpression.getBody();
if (invalidBody == null) return declaration;
final PsiLambdaExpression expressionFromText = (PsiLambdaExpression)elementFactory
.createExpressionFromText(lambdaExpression.getParameterList().getText() + " -> {}", lambdaExpression);
.createExpressionFromText(lambdaExpression.getParameterList().getText() + " -> {}", lambdaExpression.getParent());
PsiCodeBlock newBody = (PsiCodeBlock)expressionFromText.getBody();
LOG.assertTrue(newBody != null);
newBody.add(declaration);
lambdaExpression =
(PsiLambdaExpression)lambdaExpression.replace(elementFactory.createExpressionFromText(
lambdaExpression.getParameterList().getText() + " -> " + invalidBody.getText(), lambdaExpression));
final PsiElement lambdaExpressionBody = lambdaExpression.getBody();
LOG.assertTrue(lambdaExpressionBody != null);
final PsiStatement lastBodyStatement;
if (LambdaUtil.getFunctionalInterfaceReturnType(lambdaExpression) == PsiType.VOID) {
lastBodyStatement = elementFactory.createStatementFromText("a;", lambdaExpression);
@@ -255,41 +255,55 @@ public class GenericsUtil {
final PsiSubstitutor substitutor,
final PsiElement context,
final boolean allowUncheckedConversion) {
nextTypeParam:
for (PsiTypeParameter typeParameter : typeParams) {
PsiType substituted = substitutor.substitute(typeParameter);
if (substituted == null) return null;
if (context != null) {
substituted = PsiUtil.captureToplevelWildcards(substituted, context);
PsiType boundError = findTypeParameterBoundError(typeParameter, typeParameter.getExtendsListTypes(),
substitutor, context, allowUncheckedConversion);
if (boundError != null) {
return Pair.create(typeParameter, boundError);
}
}
return null;
}
PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
for (PsiClassType type : extendsTypes) {
PsiType extendsType = substitutor.substitute(type);
if (substituted instanceof PsiWildcardType) {
if (((PsiWildcardType)substituted).isSuper()) {
continue;
}
final PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound();
if (acceptExtendsBound(extendsType, extendsBound)) {
continue nextTypeParam;
}
public static PsiType findTypeParameterBoundError(PsiTypeParameter typeParameter,
PsiType[] extendsTypes,
PsiSubstitutor substitutor,
PsiElement context,
boolean allowUncheckedConversion) {
PsiType substituted = substitutor.substitute(typeParameter);
if (substituted == null) return null;
if (context != null) {
substituted = PsiUtil.captureToplevelWildcards(substituted, context);
}
if (substituted instanceof PsiWildcardType) {
if (((PsiWildcardType)substituted).isSuper()) {
return null;
}
}
for (PsiType type : extendsTypes) {
PsiType extendsType = substitutor.substitute(type);
if (substituted instanceof PsiWildcardType) {
final PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound();
if (acceptExtendsBound(extendsType, extendsBound)) {
return null;
}
else if (substituted instanceof PsiIntersectionType) {
for (PsiType extendsBound : ((PsiIntersectionType)substituted).getConjuncts()) {
if (acceptExtendsBound(extendsType, extendsBound)) continue nextTypeParam;
}
}
else if (substituted instanceof PsiIntersectionType) {
for (PsiType extendsBound : ((PsiIntersectionType)substituted).getConjuncts()) {
if (acceptExtendsBound(extendsType, extendsBound)) return null;
}
else if (substituted instanceof PsiCapturedWildcardType) {
final PsiType extendsBound = ((PsiCapturedWildcardType)substituted).getUpperBound();
if (acceptExtendsBound(extendsType, extendsBound)) {
continue nextTypeParam;
}
}
if (extendsType != null && !TypeConversionUtil.isAssignable(extendsType, substituted, allowUncheckedConversion)) {
return Pair.create(typeParameter, extendsType);
}
else if (substituted instanceof PsiCapturedWildcardType) {
final PsiType extendsBound = ((PsiCapturedWildcardType)substituted).getUpperBound();
if (acceptExtendsBound(extendsType, extendsBound)) {
return null;
}
}
if (extendsType != null && !TypeConversionUtil.isAssignable(extendsType, substituted, allowUncheckedConversion)) {
return extendsType;
}
}
return null;
}
@@ -254,12 +254,12 @@ public class InferenceSession {
}
}
final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables, mySiteSubstitutor);
final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables, PsiSubstitutor.EMPTY);
if (substitutor != null) {
if (myContext != null) {
myContext.putUserData(ERASED, myErased);
}
mySiteSubstitutor = substitutor;
mySiteSubstitutor = mySiteSubstitutor.putAll(substitutor);
for (InferenceVariable variable : myInferenceVariables) {
variable.setInstantiation(substitutor.substitute(variable.getParameter()));
}
@@ -403,7 +403,7 @@ public class InferenceSession {
}
public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) {
PsiSubstitutor substitutor = mySiteSubstitutor;
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
for (InferenceVariable variable : variables) {
final PsiType equalsBound = getEqualsBound(variable, substitutor);
if (!(equalsBound instanceof PsiPrimitiveType)) {
@@ -751,6 +751,22 @@ public class InferenceSession {
return isProperType(bound) ? bound : substitutor.substitute(bound);
}
private static boolean hasBoundProblems(final List<InferenceVariable> typeParams,
final PsiSubstitutor substitutor,
final PsiElement context) {
for (InferenceVariable typeParameter : typeParams) {
if (typeParameter.getCallContext() != context) {
continue;
}
final List<PsiType> extendsTypes = typeParameter.getBounds(InferenceBound.UPPER);
final PsiType[] bounds = extendsTypes.toArray(new PsiType[extendsTypes.size()]);
if (GenericsUtil.findTypeParameterBoundError(typeParameter, bounds, substitutor, context, true) != null) {
return true;
}
}
return false;
}
private PsiSubstitutor resolveBounds(final Collection<InferenceVariable> inferenceVariables,
PsiSubstitutor substitutor) {
final Collection<InferenceVariable> allVars = new ArrayList<InferenceVariable>(inferenceVariables);
@@ -759,8 +775,7 @@ public class InferenceSession {
if (!myIncorporationPhase.hasCaptureConstraints(vars)) {
PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor);
if (firstSubstitutor != null) {
final Set<PsiTypeParameter> parameters = firstSubstitutor.getSubstitutionMap().keySet();
if (GenericsUtil.findTypeParameterWithBoundError(parameters.toArray(new PsiTypeParameter[parameters.size()]), firstSubstitutor, myContext, true) != null) {
if (hasBoundProblems(vars, firstSubstitutor, myContext)) {
firstSubstitutor = null;
}
}
@@ -837,7 +852,7 @@ public class InferenceSession {
for (InferenceVariable var : vars) {
LOG.assertTrue(var.getInstantiation() == PsiType.NULL);
final PsiTypeParameter typeParameter = var.getParameter();
if (substitutor.getSubstitutionMap().containsKey(typeParameter) && var.getCallContext() != myContext) {
if (substitutor.putAll(mySiteSubstitutor).getSubstitutionMap().containsKey(typeParameter) && var.getCallContext() != myContext) {
continue;//todo
}
@@ -849,7 +864,7 @@ public class InferenceSession {
type = PsiType.getJavaLangRuntimeException(myManager, GlobalSearchScope.allScope(myManager.getProject()));
}
else {
if (substitutor.getSubstitutionMap().get(typeParameter) != null) continue;
if (substitutor.putAll(mySiteSubstitutor).getSubstitutionMap().get(typeParameter) != null) continue;
type = myErased ? null : getUpperBound(var, substitutor);
}
}
@@ -90,13 +90,9 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
if (method != null && !method.isConstructor()) {
returnType = method.getReturnType();
if (returnType != null) {
List<PsiTypeParameter> params = new ArrayList<PsiTypeParameter>();
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(method)) {
params.add(parameter);
}
typeParams = params.toArray(new PsiTypeParameter[params.size()]);
typeParams = method.getTypeParameters();
}
} else if (myExpression instanceof PsiNewExpression) { //default constructor
} else if (myExpression instanceof PsiNewExpression) {
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)myExpression).getClassOrAnonymousClassReference();
if (classReference != null) {
final PsiElement psiClass = classReference.resolve();
@@ -108,7 +104,9 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
}
if (typeParams != null) {
final InferenceSession callSession = new InferenceSession(typeParams, PsiSubstitutor.EMPTY, myExpression.getManager(), myExpression);
PsiSubstitutor siteSubstitutor =
resolveResult instanceof MethodCandidateInfo && method != null && !method.isConstructor() ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() : PsiSubstitutor.EMPTY;
final InferenceSession callSession = new InferenceSession(typeParams, siteSubstitutor, myExpression.getManager(), myExpression);
callSession.propagateVariables(session.getInferenceVariables());
if (method != null) {
final PsiExpression[] args = argumentList.getExpressions();
@@ -120,7 +118,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
if (!accepted) {
return false;
}
callSession.registerReturnTypeConstraints(returnType, myT);
callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), myT);
if (callSession.repeatInferencePhases(true)) {
session.registerNestedSession(callSession);
} else {
@@ -91,7 +91,7 @@ public class TypeEqualityConstraint implements ConstraintFormula {
final PsiClassType.ClassResolveResult sResult = ((PsiClassType)myS).resolveGenerics();
final PsiClass tClass = tResult.getElement();
//equal erasure
if (tClass != null && tClass.equals(sResult.getElement())) {
if (tClass != null && tClass.getManager().areElementsEquivalent(tClass, sResult.getElement())) {
final PsiSubstitutor tSubstitutor = tResult.getSubstitutor();
final PsiSubstitutor sSubstitutor = sResult.getSubstitutor();
for (PsiTypeParameter typeParameter : tClass.getTypeParameters()) {
@@ -0,0 +1,66 @@
class Test {
final Runnable runnable;
{
runnable = () -> System.out.println(<error descr="Variable 'runnable' might not have been initialized">runnable</error>);
}
final Runnable runnable1;
{
runnable1 = new Runnable() {
@Override
public void run() {
System.out.println(runnable1);
}
};
}
}
abstract class TestInnerAnonymous {
void foo() {
new Object() {
final Runnable runnable;
{
runnable = () -> System.out.println(<error descr="Variable 'runnable' might not have been initialized">runnable</error>);
}
final Runnable runnable1;
{
runnable1 = new Runnable() {
@Override
public void run() {
System.out.println(runnable1);
}
};
}
};
}
private static class MyObject {
final Runnable runnable;
{
runnable = () -> System.out.println(<error descr="Variable 'runnable' might not have been initialized">runnable</error>);
}
final Runnable runnable1;
{
runnable1 = new Runnable() {
@Override
public void run() {
System.out.println(runnable1);
}
};
}
}
}
@@ -0,0 +1,49 @@
import java.util.Map;
import java.util.List;
//expected type parameter
class Sample<V> {
public <K> Map<V, K> test() {
return null;
}
public <T> void fun(T t, V v) {
}
<M> M bar() {
return null;
}
void run(Sample<Integer> sample) {
fun(test(), bar());
sample.fun(test(), sample.bar());
sample.fun(test(), bar());
fun(test(), sample.bar());
fun(sample.test(), bar());
fun(sample.test(), sample.bar());
sample.fun(sample.test(), bar());
sample.fun(sample.test(), sample.bar());
}
}
//expected generic type
class Sample1<T> {
public <S extends T> List<S> reverse() {
return null;
}
public void foo(Sample1<Comparable> t)
{
newTreeSet(t.reverse());
newTreeSet(reverse());
t.newTreeSet(t.reverse());
t.newTreeSet(reverse());
}
public <E> void newTreeSet(List<E> comparator) {}
}
@@ -67,7 +67,7 @@ class MyTest1 {
}
public static void main(String[] args) {
m<error descr="Ambiguous method call: both 'MyTest1.m(I1)' and 'MyTest1.m(I2)' match">(Foo::new)</error>;
m<error descr="Ambiguous method call: both 'MyTest1.m(I2)' and 'MyTest1.m(I3)' match">(Foo::new)</error>;
}
}
class MyTest2 {
@@ -104,6 +104,6 @@ class MyTest2 {
}
public static void main(String[] args) {
m<error descr="Ambiguous method call: both 'MyTest2.m(I1)' and 'MyTest2.m(I2)' match">(Foo::new)</error>;
m<error descr="Ambiguous method call: both 'MyTest2.m(I2)' and 'MyTest2.m(I3)' match">(Foo::new)</error>;
}
}
@@ -0,0 +1,10 @@
class Sample {
void a() {
System.out.println("");
<caret>}
private int foo() {
return 1;
}
}
@@ -0,0 +1,12 @@
class Sample {
void a() {
class Local {
<caret>}
}
private int foo() {
return 1;
}
}
@@ -0,0 +1,7 @@
class Sample {
static {<caret>}
int foo() {
return 1;
}
}
@@ -0,0 +1,7 @@
class Sample {
int <caret>i = 0;
int foo() {
return 1;
}
}
@@ -0,0 +1,9 @@
class Sample {
public Sample() {
<caret>super();
}
int foo() {
return 1;
}
}
@@ -0,0 +1,20 @@
class Foo {
interface I<T> {
T m(Object op);
}
interface J<T> {
int m(T o);
}
void f(J r) {}
void f(I<String> r) {}
{
f((Object a) -> {
int c = 1;
return c;
});
}
}
@@ -0,0 +1,17 @@
class Foo {
interface I<T> {
T m(Object op);
}
interface J<T> {
int m(T o);
}
void f(J r) {}
void f(I<String> r) {}
{
f((Object a) -> <selection>1</selection>);
}
}
@@ -0,0 +1,20 @@
class Foo {
interface I<T> {
T m(Object op);
}
interface J<T> {
void m(T o);
}
void f(J r) {}
void f(I<String> r) {}
{
f((a) -> {
int c = 1;
return c;
});
}
}
@@ -0,0 +1,17 @@
class Foo {
interface I<T> {
T m(Object op);
}
interface J<T> {
void m(T o);
}
void f(J r) {}
void f(I<String> r) {}
{
f((a) -> <selection>1</selection>);
}
}
@@ -172,6 +172,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
doTest();
}
public void testSiteSubstitutionInExpressionConstraints() throws Exception {
doTest();
}
public void testIncorporationWithEqualsBoundsSubstitution() throws Exception {
doTest();
}
@@ -39,6 +39,10 @@ public class LightAdvHighlightingJdk8Test extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testFinalVariableMightNotHaveBeenInitializedInsideLambda() throws Exception {
doTest();
}
private void doTest() {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
doTest(BASE_PATH + "/" + getTestName(false) + ".java", true, false);
@@ -83,9 +83,10 @@ class Test {
expected: '''\
class Test {
public int j;
{ j = 1; }
protected int k;
private int i;
{ j = 1; }
}''',
rules: [rule(FIELD, PUBLIC), rule(FIELD, PROTECTED), rule(FIELD, PRIVATE)])
}
@@ -101,10 +102,11 @@ class Test {
}''',
expected: '''\
class Test {
{ j = 1; }
public int j;
protected int k;
private int i;
{ j = 1; }
}''',
rules: [rule(FIELD, PUBLIC), rule(FIELD, PROTECTED), rule(FIELD, PRIVATE)])
}
@@ -569,4 +569,85 @@ class B extends A {
rules: [rule(PUBLIC, METHOD), rule(PRIVATE, METHOD)]
)
}
void "test initializer block after fields"() {
doTest(
initial: '''\
public class NewOneClass {
{
a = 1;
}
int a;
{
b = 5;
}
int b;
}
''',
expected: '''\
public class NewOneClass {
int a;
int b;
{
a = 1;
}
{
b = 5;
}
}
''',
rules: [rule(FIELD), rule(INIT_BLOCK)]
)
}
void "test static initializer block"() {
doTest(
initial: '''\
public class NewOneClass {
static {
a = 1;
}
static int a;
{
b = 5;
}
int b;
}
''',
expected: '''\
public class NewOneClass {
static int a;
static {
a = 1;
}
int b;
{
b = 5;
}
}
''',
rules: [rule(STATIC, FIELD), rule(STATIC, INIT_BLOCK), rule(FIELD), rule(INIT_BLOCK)]
)
}
}
@@ -25,6 +25,7 @@ public class JavaFormatterBlankLinesTest extends AbstractJavaFormatterTest {
public void testBlankLinesAroundClassInitializationBlock() throws Exception {
getSettings().BLANK_LINES_AROUND_METHOD = 3;
getJavaSettings().BLANK_LINES_AROUND_INITIALIZER = 3;
doTextTest(
"class T {\n" +
" private final DecimalFormat fmt = new DecimalFormat();\n" +
@@ -260,7 +260,6 @@ public class JavaFormatterWrapTest extends AbstractJavaFormatterTest {
);
}
@Bombed(user = "Roman Shevchenko", year = 2014, month = Calendar.MARCH, day = 14)
public void testWrapMethodAnnotationBeforeParams() {
// Inspired by IDEA-59536
getSettings().RIGHT_MARGIN = 90;
@@ -214,6 +214,56 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase {
" }", false);
}
public void testOnClosingBrace() throws Exception {
doTest(" foo()", "int result = new Test().invoke();",
"public class Test {\n" +
" public int invoke() {\n" +
" return foo();\n" +
" }\n" +
" }");
}
public void testOnClosingBraceLocalClass() throws Exception {
doTest(" foo()", "int result = new Test().invoke();",
"public class Test {\n" +
" public int invoke() {\n" +
" return foo();\n" +
" }\n" +
" }");
}
public void testOnFieldInitialization() throws Exception {
doTest(" foo()", "int result = new Test().invoke();",
"public class Test {\n" +
" public int invoke() {\n" +
" return foo();\n" +
" }\n" +
" }");
}
public void testOnEmptyMethod() throws Exception {
doTest(" foo()", "int result = Test.invoke();",
"public static class Test {\n" +
" public static int invoke() {\n" +
" return foo();\n" +
" }\n" +
" }");
}
public void testOnSuperConstructorCall() throws Exception {
doTest(" foo()", "int result = new Test().invoke();",
"public class Test {\n" +
" public int invoke() {\n" +
" return foo();\n" +
" }\n" +
" }");
}
@Override
protected Sdk getProjectJDK() {
return IdeaTestUtil.getMockJdk18();
@@ -437,6 +437,14 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
doTest(new MockIntroduceVariableHandler("c", false, false, false, "int"));
}
public void testPutInLambdaBody() {
doTest(new MockIntroduceVariableHandler("c", false, false, false, "int"));
}
public void testPutInLambdaBodyVoidValueConflict() {
doTest(new MockIntroduceVariableHandler("c", false, false, false, "int"));
}
public void testNormalizeDeclarations() {
doTest(new MockIntroduceVariableHandler("i3", false, false, false, "int"));
}
@@ -15,14 +15,17 @@
*/
package org.jetbrains.jps.api;
import java.util.concurrent.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author Eugene Zhuravlev
* Date: 5/3/12
*/
public class BasicFuture<T> implements Future<T> {
public class BasicFuture<T> implements TaskFuture<T> {
protected final Semaphore mySemaphore = new Semaphore(1);
private final AtomicBoolean myDone = new AtomicBoolean(false);
private final AtomicBoolean myCanceledState = new AtomicBoolean(false);
@@ -0,0 +1,25 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jps.api;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public interface TaskFuture<T> extends Future<T> {
void waitFor();
boolean waitFor(long timeout, TimeUnit unit);
}
@@ -2347,6 +2347,13 @@ public class Mappings {
}
}
@Nullable
public Collection<File> getClassSources(int className) {
synchronized (myLock) {
return myClassToSourceFile.get(className);
}
}
public void close() {
synchronized (myLock) {
myClassToSubclasses.close();
@@ -16,6 +16,7 @@
package org.jetbrains.jps.cmdline;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileSystemUtil;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import io.netty.bootstrap.Bootstrap;
@@ -35,7 +36,11 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.api.CmdlineProtoUtil;
import org.jetbrains.jps.api.CmdlineRemoteProto;
import org.jetbrains.jps.api.GlobalOptions;
import org.jetbrains.jps.incremental.MessageHandler;
import org.jetbrains.jps.incremental.Utils;
import org.jetbrains.jps.incremental.fs.BuildFSState;
import org.jetbrains.jps.incremental.fs.FSState;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.service.SharedThreadPool;
import java.io.*;
@@ -49,6 +54,9 @@ import java.util.concurrent.TimeUnit;
*/
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public class BuildMain {
private static final String PRELOAD_PROJECT_PATH = "preload.project.path";
private static final String PRELOAD_CONFIG_PATH = "preload.config.path";
private static final String LOG_CONFIG_FILE_NAME = "build-log.xml";
private static final String LOG_FILE_NAME = "build.log";
private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml";
@@ -65,19 +73,10 @@ public class BuildMain {
private static final int SYSTEM_DIR_ARG = SESSION_ID_ARG + 1;
private static NioEventLoopGroup ourEventLoopGroup;
@Nullable
private static PreloadedData ourPreloadedData;
public static void main(String[] args){
final long start = System.nanoTime();
Runtime.getRuntime().addShutdownHook(new Thread("TimeLogger"){
public void run() {
final long totalTime = (System.nanoTime() - start) / 1000000L;
final long millis = totalTime % 1000L ;
final long seconds = totalTime / 1000L;
LOG.info("Total build time " + seconds + " sec " + millis + " ms");
}
});
System.out.println("Build process started. Classpath: " + System.getProperty("java.class.path"));
final String host = args[HOST_ARG];
final int port = Integer.parseInt(args[PORT_ARG]);
@@ -123,6 +122,60 @@ public class BuildMain {
final ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)).awaitUninterruptibly();
final boolean success = future.isSuccess();
if (success) {
final String projectPathToPreload = System.getProperty(PRELOAD_PROJECT_PATH, null);
final String globalsPathToPreload = System.getProperty(PRELOAD_CONFIG_PATH, null);
if (projectPathToPreload != null && globalsPathToPreload != null) {
final long preloadStart = System.currentTimeMillis();
final PreloadedData data = new PreloadedData();
ourPreloadedData = data;
try {
FileSystemUtil.getAttributes(projectPathToPreload); // this will pre-load all FS optimizations
final BuildRunner runner = new BuildRunner(new JpsModelLoaderImpl(projectPathToPreload, globalsPathToPreload, null));
data.setRunner(runner);
final File dataStorageRoot = Utils.getDataStorageRoot(projectPathToPreload);
final BuildFSState fsState = new BuildFSState(false);
final ProjectDescriptor pd = runner.load(new MessageHandler() {
@Override
public void processMessage(BuildMessage msg) {
data.addMessage(msg);
}
}, dataStorageRoot, fsState);
data.setProjectDescriptor(pd);
try {
final File fsStateFile = new File(dataStorageRoot, BuildSession.FS_STATE_FILE);
final DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(fsStateFile)));
try {
final int version = in.readInt();
if (version == FSState.VERSION) {
final long savedOrdinal = in.readLong();
in.readBoolean(); // must skip "has-work-to-do" flag
fsState.load(in, pd.getModel(), pd.getBuildRootIndex());
data.setFsEventOrdinal(savedOrdinal);
}
}
finally {
in.close();
}
}
catch (FileNotFoundException ignored) {
}
catch (IOException e) {
LOG.info("Error pre-loading FS state", e);
fsState.clearAll();
}
LOG.info("Pre-loaded project model in " + (System.currentTimeMillis() - preloadStart) + " ms");
}
catch (Throwable e) {
LOG.info("Failed to pre-load project " + projectPathToPreload, e);
// just failed to preload the project, the situation will be handled later, when real build starts
}
}
else if (projectPathToPreload != null || globalsPathToPreload != null){
LOG.info("Skipping project pre-loading step: both paths to project configuration files and path to global settings must be specified");
}
future.channel().writeAndFlush(CmdlineProtoUtil.toMessage(sessionId, CmdlineProtoUtil.createParamRequest()));
}
else {
@@ -159,7 +212,7 @@ public class BuildMain {
case BUILD_PARAMETERS: {
if (mySession == null) {
final CmdlineRemoteProto.Message.ControllerMessage.FSEvent delta = controllerMessage.hasFsEvent()? controllerMessage.getFsEvent() : null;
final BuildSession session = new BuildSession(mySessionId, channel, controllerMessage.getParamsMessage(), delta);
final BuildSession session = new BuildSession(mySessionId, channel, controllerMessage.getParamsMessage(), delta, ourPreloadedData);
mySession = session;
SharedThreadPool.getInstance().executeOnPooledThread(new Runnable() {
@Override
@@ -58,14 +58,20 @@ public class BuildRunner {
public static final boolean PARALLEL_BUILD_ENABLED = Boolean.parseBoolean(System.getProperty(GlobalOptions.COMPILE_PARALLEL_OPTION, "false"));
private static final boolean STORE_TEMP_CACHES_IN_MEMORY = PARALLEL_BUILD_ENABLED || Boolean.valueOf(System.getProperty(GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION, "true"));
private final JpsModelLoader myModelLoader;
private final List<String> myFilePaths;
private final Map<String, String> myBuilderParams;
private List<String> myFilePaths = Collections.emptyList();
private Map<String, String> myBuilderParams = Collections.emptyMap();
private boolean myForceCleanCaches;
public BuildRunner(JpsModelLoader modelLoader, List<String> filePaths, Map<String, String> builderParams) {
public BuildRunner(JpsModelLoader modelLoader) {
myModelLoader = modelLoader;
myFilePaths = filePaths;
myBuilderParams = builderParams;
}
public void setFilePaths(List<String> filePaths) {
myFilePaths = filePaths != null? filePaths : Collections.<String>emptyList();
}
public void setBuilderParams(Map<String, String> builderParams) {
myBuilderParams = builderParams != null? builderParams : Collections.<String, String>emptyMap();
}
public ProjectDescriptor load(MessageHandler msgHandler, File dataStorageRoot, BuildFSState fsState) throws IOException {
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.concurrency.SequentialTaskExecutor;
import com.intellij.util.io.DataOutputStream;
import io.netty.channel.Channel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.TimingLog;
import org.jetbrains.jps.api.*;
@@ -57,9 +58,11 @@ import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage
*/
final class BuildSession implements Runnable, CanceledStatus {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.cmdline.BuildSession");
private static final String FS_STATE_FILE = "fs_state.dat";
public static final String FS_STATE_FILE = "fs_state.dat";
private final UUID mySessionId;
private final Channel myChannel;
@Nullable
private final PreloadedData myPreloadedData;
private volatile boolean myCanceled = false;
private final String myProjectPath;
@Nullable
@@ -70,6 +73,7 @@ final class BuildSession implements Runnable, CanceledStatus {
private volatile ProjectDescriptor myProjectDescriptor;
private final Map<Pair<String, String>, ConstantSearchFuture> mySearchTasks = Collections.synchronizedMap(new HashMap<Pair<String, String>, ConstantSearchFuture>());
private final ConstantSearch myConstantSearch = new ConstantSearch();
@NotNull
private final BuildRunner myBuildRunner;
private final boolean myForceModelLoading;
private final BuildType myBuildType;
@@ -78,24 +82,31 @@ final class BuildSession implements Runnable, CanceledStatus {
BuildSession(UUID sessionId,
Channel channel,
CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage params,
@Nullable CmdlineRemoteProto.Message.ControllerMessage.FSEvent delta) {
@Nullable CmdlineRemoteProto.Message.ControllerMessage.FSEvent delta, @Nullable PreloadedData preloaded) {
mySessionId = sessionId;
myChannel = channel;
myPreloadedData = preloaded;
final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals = params.getGlobalSettings();
myProjectPath = FileUtil.toCanonicalPath(params.getProjectId());
String globalOptionsPath = FileUtil.toCanonicalPath(globals.getGlobalOptionsPath());
myBuildType = convertCompileType(params.getBuildType());
myScopes = params.getScopeList();
List<String> filePaths = params.getFilePathList();
Map<String, String> builderParams = new HashMap<String, String>();
final Map<String, String> builderParams = new HashMap<String, String>();
for (CmdlineRemoteProto.Message.KeyValuePair pair : params.getBuilderParameterList()) {
builderParams.put(pair.getKey(), pair.getValue());
}
myInitialFSDelta = delta;
JpsModelLoaderImpl loader = new JpsModelLoaderImpl(myProjectPath, globalOptionsPath, null);
myForceModelLoading = Boolean.parseBoolean(builderParams.get(BuildParametersKeys.FORCE_MODEL_LOADING));
myBuildRunner = new BuildRunner(loader, filePaths, builderParams);
if (preloaded == null || preloaded.getRunner() == null) {
myBuildRunner = new BuildRunner(new JpsModelLoaderImpl(myProjectPath, globalOptionsPath, null));
}
else {
myBuildRunner = preloaded.getRunner();
}
myBuildRunner.setFilePaths(filePaths);
myBuildRunner.setBuilderParams(builderParams);
myForceModelLoading = (preloaded != null && preloaded.getProjectDescriptor() != null) || Boolean.parseBoolean(builderParams.get(BuildParametersKeys.FORCE_MODEL_LOADING));
}
@Override
@@ -185,8 +196,9 @@ final class BuildSession implements Runnable, CanceledStatus {
// invoked the very first time for this project
myBuildRunner.setForceCleanCaches(true);
}
final DataInputStream fsStateStream = createFSDataStream(dataStorageRoot);
final ProjectDescriptor preloadedProject = myPreloadedData != null? myPreloadedData.getProjectDescriptor() : null;
final DataInputStream fsStateStream =
preloadedProject != null || myInitialFSDelta == null /*this will force FS rescan*/? null : createFSDataStream(dataStorageRoot, myInitialFSDelta.getOrdinal());
if (fsStateStream != null) {
// optimization: check whether we can skip the build
@@ -198,27 +210,56 @@ final class BuildSession implements Runnable, CanceledStatus {
}
}
final BuildFSState fsState = new BuildFSState(false);
final BuildFSState fsState = preloadedProject != null? preloadedProject.fsState : new BuildFSState(false);
try {
final ProjectDescriptor pd = myBuildRunner.load(msgHandler, dataStorageRoot, fsState);
TimingLog.LOG.debug("Project descriptor loaded");
myProjectDescriptor = pd;
if (fsStateStream != null) {
try {
try {
fsState.load(fsStateStream, pd.getModel(), pd.getBuildRootIndex());
applyFSEvent(pd, myInitialFSDelta, false);
TimingLog.LOG.debug("FS Delta loaded");
}
finally {
fsStateStream.close();
final ProjectDescriptor pd;
if (preloadedProject != null) {
pd = preloadedProject;
final List<BuildMessage> preloadMessages = myPreloadedData.getLoadMessages();
if (!preloadMessages.isEmpty()) {
// replay preload-time messages, so that they are delivered to the IDE
for (BuildMessage message : preloadMessages) {
msgHandler.processMessage(message);
}
}
catch (Throwable e) {
LOG.error(e);
fsState.clearAll();
if (myInitialFSDelta == null || myPreloadedData.getFsEventOrdinal() + 1L != myInitialFSDelta.getOrdinal()) {
// FS rescan was forced
fsState.clearAll();
}
else {
// apply events to already loaded state
try {
applyFSEvent(pd, myInitialFSDelta, false);
}
catch (Throwable e) {
LOG.error(e);
fsState.clearAll();
}
}
}
else {
// standard case
pd = myBuildRunner.load(msgHandler, dataStorageRoot, fsState);
TimingLog.LOG.debug("Project descriptor loaded");
if (fsStateStream != null) {
try {
try {
fsState.load(fsStateStream, pd.getModel(), pd.getBuildRootIndex());
applyFSEvent(pd, myInitialFSDelta, false);
TimingLog.LOG.debug("FS Delta loaded");
}
finally {
fsStateStream.close();
}
}
catch (Throwable e) {
LOG.error(e);
fsState.clearAll();
}
}
}
myProjectDescriptor = pd;
myLastEventOrdinal = myInitialFSDelta != null? myInitialFSDelta.getOrdinal() : 0L;
// free memory
@@ -469,11 +510,7 @@ final class BuildSession implements Runnable, CanceledStatus {
}
@Nullable
private DataInputStream createFSDataStream(File dataStorageRoot) {
if (myInitialFSDelta == null) {
// this will force FS rescan
return null;
}
private static DataInputStream createFSDataStream(File dataStorageRoot, final long currentEventOrdinal) {
try {
final File file = new File(dataStorageRoot, FS_STATE_FILE);
byte[] bytes;
@@ -490,7 +527,7 @@ final class BuildSession implements Runnable, CanceledStatus {
return null;
}
final long savedOrdinal = in.readLong();
if (savedOrdinal + 1L != myInitialFSDelta.getOrdinal()) {
if (savedOrdinal + 1L != currentEventOrdinal) {
return null;
}
return in;
@@ -0,0 +1,71 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jps.cmdline;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import java.util.ArrayList;
import java.util.List;
/**
* @author Eugene Zhuravlev
* Date: 22-Oct-14
*/
public class PreloadedData {
@Nullable
private BuildRunner runner;
@Nullable
private ProjectDescriptor projectDescriptor;
private final List<BuildMessage> loadMessages = new ArrayList<BuildMessage>();
private long fsEventOrdinal;
@Nullable
public BuildRunner getRunner() {
return runner;
}
public void setRunner(@Nullable BuildRunner runner) {
this.runner = runner;
}
@Nullable
public ProjectDescriptor getProjectDescriptor() {
return projectDescriptor;
}
public void setProjectDescriptor(@Nullable ProjectDescriptor projectDescriptor) {
this.projectDescriptor = projectDescriptor;
}
public long getFsEventOrdinal() {
return fsEventOrdinal;
}
public void setFsEventOrdinal(long fsEventOrdinal) {
this.fsEventOrdinal = fsEventOrdinal;
}
public List<BuildMessage> getLoadMessages() {
return loadMessages;
}
public void addMessage(BuildMessage msg) {
loadMessages.add(msg);
}
}
@@ -168,7 +168,16 @@ public class JavacMain {
diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage()));
}
catch (CompilationCanceledException ignored) {
diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.OTHER, "Compilation was canceled"));
handleCancelException(diagnosticConsumer);
}
catch (RuntimeException e) {
final Throwable cause = e.getCause();
if (cause instanceof CompilationCanceledException) {
handleCancelException(diagnosticConsumer);
}
else {
throw e;
}
}
finally {
fileManager.close();
@@ -179,6 +188,10 @@ public class JavacMain {
return false;
}
private static void handleCancelException(DiagnosticOutputConsumer diagnosticConsumer) {
diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.OTHER, "Compilation was canceled"));
}
private static List<JavaSourceTransformer> getSourceTransformers() {
final Class<JavaSourceTransformer> transformerClass = JavaSourceTransformer.class;
final ServiceLoader<JavaSourceTransformer> loader = ServiceLoader.load(transformerClass, transformerClass.getClassLoader());
@@ -15,6 +15,7 @@
*/
package org.jetbrains.jps.model.serialization;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtilRt;
@@ -30,6 +31,8 @@ import java.io.IOException;
* @author nik
*/
public abstract class JpsLoaderBase {
private static final Logger LOG = Logger.getInstance(JpsLoaderBase.class);
private static final int MAX_ATTEMPTS = 5;
private final JpsMacroExpander myMacroExpander;
protected JpsLoaderBase(JpsMacroExpander macroExpander) {
@@ -66,7 +69,7 @@ public abstract class JpsLoaderBase {
protected static Element loadRootElement(final File file, final JpsMacroExpander macroExpander) {
try {
final Element element = JDOMUtil.loadDocument(file).getRootElement();
final Element element = tryLoadRootElement(file);
macroExpander.substitute(element, SystemInfo.isFileSystemCaseSensitive);
return element;
}
@@ -78,6 +81,24 @@ public abstract class JpsLoaderBase {
}
}
private static Element tryLoadRootElement(File file) throws IOException, JDOMException {
for (int i = 0; i < MAX_ATTEMPTS - 1; i++) {
try {
return JDOMUtil.loadDocument(file).getRootElement();
}
catch (Exception e) {
LOG.info("Loading attempt #" + i + " failed", e);
}
//most likely configuration file is being written by IDE so we'll wait a little
try {
//noinspection BusyWait
Thread.sleep(300);
}
catch (InterruptedException ignored) { }
}
return JDOMUtil.loadDocument(file).getRootElement();
}
protected static boolean isXmlFile(File file) {
return file.isFile() && FileUtilRt.extensionEquals(file.getName(), "xml");
}
@@ -193,8 +193,7 @@ public class Standalone {
public static void runBuild(JpsModelLoader loader, File dataStorageRoot, MessageHandler messageHandler, List<TargetTypeBuildScope> scopes,
boolean includeDependenciesToScope) throws Exception {
final BuildRunner buildRunner = new BuildRunner(loader, Collections.<String>emptyList(), Collections.<String, String>emptyMap()
);
final BuildRunner buildRunner = new BuildRunner(loader);
ProjectDescriptor descriptor = buildRunner.load(messageHandler, dataStorageRoot, new BuildFSState(true));
try {
buildRunner.runBuild(descriptor, CanceledStatus.NULL, null, messageHandler, BuildType.BUILD, scopes, includeDependenciesToScope);
@@ -1,6 +1,7 @@
package com.intellij.json.psi.impl;
import com.intellij.json.JsonLanguage;
import com.intellij.json.psi.JsonFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
@@ -20,6 +21,8 @@ public class JsonTreeChangePreprocessor implements PsiTreeChangePreprocessor {
*/
@Override
public void treeChanged(@NotNull PsiTreeChangeEventImpl event) {
if (!(event.getFile() instanceof JsonFile)) return;
final PsiElement element = event.getParent();
if (element == null || !(element.getManager() instanceof PsiManagerImpl)) {
return;
@@ -66,7 +66,9 @@ public class JsonStructureViewTest extends JsonTestCase {
" -object\n" +
" nestedObject\n" +
" -array\n" +
" +array\n" +
" -array\n" +
" -object\n" +
" deepNestedObject\n" +
" -object\n" +
" siblingObject\n");
}
+1 -1
View File
@@ -52,7 +52,7 @@ netty-all-4.1.0.Beta3.jar
oromatcher.jar
picocontainer.jar
protobuf-2.5.0.jar
proxy-vole_20120920.jar
proxy-vole_20131209.jar
pty4j-0.3.jar
purejavacomm.jar
resolver.jar
@@ -0,0 +1,83 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class WelcomeWizardUtil {
private static volatile String ourDefaultLAF;
private static volatile String ourWizardLAF;
private static volatile String ourWizardMacKeymap;
private static volatile String ourWizardEditorScheme;
private static volatile Boolean ourAutoScrollToSource;
private static volatile Set<String> ourFeaturedPluginsToInstall = new HashSet<String>();
public static void setDefaultLAF(String laf) {
ourDefaultLAF = laf;
}
public static String getDefaultLAF() {
return ourDefaultLAF;
}
public static void setWizardLAF(String laf) {
ourWizardLAF = laf;
}
public static String getWizardLAF() {
return ourWizardLAF;
}
public static void setWizardKeymap(@Nullable String keymap) {
ourWizardMacKeymap = keymap;
}
@Nullable
public static String getWizardMacKeymap() {
return ourWizardMacKeymap;
}
public static void setWizardEditorScheme(@Nullable String wizardEditorScheme) {
ourWizardEditorScheme = wizardEditorScheme;
}
@Nullable
public static String getWizardEditorScheme() {
return ourWizardEditorScheme;
}
@Nullable
public static Boolean getAutoScrollToSource() {
return ourAutoScrollToSource;
}
public static void setAutoScrollToSource(@Nullable Boolean autoScrollToSource) {
ourAutoScrollToSource = autoScrollToSource;
}
public static Set<String> getFeaturedPluginsToInstall() {
return Collections.unmodifiableSet(ourFeaturedPluginsToInstall);
}
public static void setFeaturedPluginsToInstall(Set<String> pluginsToInstall) {
ourFeaturedPluginsToInstall.clear();
ourFeaturedPluginsToInstall.addAll(pluginsToInstall);
}
}
@@ -23,7 +23,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
class FCTSBackedLighterAST extends LighterAST {
public class FCTSBackedLighterAST extends LighterAST {
private final FlyweightCapableTreeStructure<LighterASTNode> myTreeStructure;
public FCTSBackedLighterAST(final CharTable charTable, final FlyweightCapableTreeStructure<LighterASTNode> treeStructure) {
@@ -17,6 +17,7 @@ package com.intellij.lang;
import com.intellij.util.CharTable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Top-level node in AST, corresponds to PsiFile.
@@ -28,4 +29,7 @@ public interface FileASTNode extends ASTNode {
CharTable getCharTable();
boolean isParsed();
@Nullable
LighterAST getLighterAST();
}
@@ -15,8 +15,6 @@
*/
package com.intellij.lang;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.psi.tree.ILightStubFileElementType;
import com.intellij.util.CharTable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -46,19 +44,4 @@ public abstract class LighterAST {
@NotNull
public abstract List<LighterASTNode> getChildren(@NotNull final LighterASTNode parent);
public static @Nullable LighterAST getLighterASTFromFileAST(@NotNull FileASTNode node, @NotNull Language language) {
final IFileElementType contentType = LanguageParserDefinitions.INSTANCE.forLanguage(language).getFileNodeType();
assert contentType instanceof ILightStubFileElementType;
final LighterAST tree;
if (!node.isParsed()) {
final ILightStubFileElementType<?> type = (ILightStubFileElementType)contentType;
tree = new FCTSBackedLighterAST(node.getCharTable(), type.parseContentsLight(node));
}
else {
tree = new TreeBackedLighterAST(node);
}
return tree;
}
}
@@ -47,7 +47,7 @@ public class LightStubBuilder implements StubBuilder {
LOG.error("File is not of ILightStubFileElementType: " + contentType + ", " + file);
return null;
}
final LighterAST tree = LighterAST.getLighterASTFromFileAST(file.getNode(), language);
final LighterAST tree = file.getNode().getLighterAST();
if (tree == null) return null;
final StubElement rootStub = createStubForFile(file, tree);
@@ -30,7 +30,10 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.StreamUtil;
import com.intellij.openapi.util.io.ZipFileCache;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.PlatformUtilsCore;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.execution.ParametersListUtil;
@@ -166,7 +169,7 @@ public class PluginManagerCore {
return app != null && app.isUnitTestMode();
}
public static void savePluginsList(Collection<String> ids, boolean append, File plugins) throws IOException {
public static void savePluginsList(@NotNull Collection<String> ids, boolean append, @NotNull File plugins) throws IOException {
if (!plugins.isFile()) {
FileUtil.ensureCanCreateFile(plugins);
}
@@ -700,7 +703,13 @@ public class PluginManagerCore {
List<IdeaPluginDescriptorImpl> result,
@Nullable StartupProgress progress,
int pluginsCount) {
final File pluginsHome = new File(pluginsPath);
loadDescriptors(new File(pluginsPath), result, progress, pluginsCount);
}
public static void loadDescriptors(@NotNull File pluginsHome,
List<IdeaPluginDescriptorImpl> result,
@Nullable StartupProgress progress,
int pluginsCount) {
final File[] files = pluginsHome.listFiles();
if (files != null) {
int i = result.size();
@@ -89,6 +89,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
private final ASTNode myOriginalTree;
private final MyTreeStructure myParentLightTree;
private final int myOffset;
private static TokenSet ourAnyLanguageWhitespaceTokens = TokenSet.EMPTY;
@@ -132,7 +133,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@Nullable ASTNode originalTree,
@Nullable MyTreeStructure parentLightTree) {
this(project, containingFile, parserDefinition.getWhitespaceTokens(), parserDefinition.getCommentTokens(), lexer, charTable, text,
originalTree, parentLightTree);
originalTree, parentLightTree, 0);
}
public PsiBuilderImpl(Project project,
@@ -144,6 +145,19 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@NotNull final CharSequence text,
@Nullable ASTNode originalTree,
@Nullable MyTreeStructure parentLightTree) {
this(project, containingFile, whiteSpaces, comments, lexer, charTable, text, originalTree, parentLightTree, 0);
}
private PsiBuilderImpl(Project project,
PsiFile containingFile,
@NotNull TokenSet whiteSpaces,
@NotNull TokenSet comments,
@NotNull Lexer lexer,
CharTable charTable,
@NotNull final CharSequence text,
@Nullable ASTNode originalTree,
@Nullable MyTreeStructure parentLightTree,
int offset) {
myProject = project;
myFile = containingFile;
@@ -156,6 +170,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
myCharTable = charTable;
myOriginalTree = originalTree;
myParentLightTree = parentLightTree;
myOffset = offset;
cacheLexemes();
}
@@ -174,8 +189,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@NotNull final Lexer lexer,
@NotNull final LighterLazyParseableNode chameleon,
@NotNull final CharSequence text) {
this(project, chameleon.getContainingFile(), parserDefinition, lexer, chameleon.getCharTable(), text,
null, ((LazyParseableToken)chameleon).myParent);
this(project, chameleon.getContainingFile(), parserDefinition.getWhitespaceTokens(), parserDefinition.getCommentTokens(), lexer,
chameleon.getCharTable(), text, null, ((LazyParseableToken)chameleon).myParent, chameleon.getStartOffset());
}
private void cacheLexemes() {
@@ -335,12 +350,12 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@Override
public int getStartOffset() {
return myBuilder.myLexStarts[myLexemeIndex];
return myBuilder.myLexStarts[myLexemeIndex] + myBuilder.myOffset;
}
@Override
public int getEndOffset() {
return myBuilder.myLexStarts[myDoneMarker.myLexemeIndex];
return myBuilder.myLexStarts[myDoneMarker.myLexemeIndex] + myBuilder.myOffset;
}
@Override
@@ -487,12 +502,12 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@Override
public int getEndOffset() {
return myTokenEnd;
return myTokenEnd + myBuilder.myOffset;
}
@Override
public int getStartOffset() {
return myTokenStart;
return myTokenStart + myBuilder.myOffset;
}
public CharSequence getText() {
@@ -636,12 +651,12 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@Override
public int getEndOffset() {
return myBuilder.myLexStarts[myLexemeIndex];
return myBuilder.myLexStarts[myLexemeIndex] + myBuilder.myOffset;
}
@Override
public int getStartOffset() {
return myBuilder.myLexStarts[myLexemeIndex];
return myBuilder.myLexStarts[myLexemeIndex] + myBuilder.myOffset;
}
@Override
@@ -1474,6 +1489,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
private final LimitedPool<Token> myPool;
private final LimitedPool<LazyParseableToken> myLazyPool;
private final StartMarker myRoot;
private final int myOffset;
public MyTreeStructure(@NotNull StartMarker root, @Nullable final MyTreeStructure parentTree) {
if (parentTree == null) {
@@ -1499,10 +1515,12 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
return new LazyParseableToken();
}
});
myOffset = 0;
}
else {
myPool = parentTree.myPool;
myLazyPool = parentTree.myLazyPool;
myOffset = parentTree.getRoot().getStartOffset();
}
myRoot = root;
}
@@ -16,16 +16,19 @@
package com.intellij.psi.impl.source.tree;
import com.intellij.lang.ASTNode;
import com.intellij.lang.FileASTNode;
import com.intellij.lang.*;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.impl.source.CharTableImpl;
import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.psi.tree.ILightStubFileElementType;
import com.intellij.util.CharTable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class FileElement extends LazyParseableElement implements FileASTNode, Getter<FileElement> {
private volatile CharTable myCharTable = new CharTableImpl();
@@ -47,6 +50,35 @@ public class FileElement extends LazyParseableElement implements FileASTNode, Ge
return myCharTable;
}
private static final Key<LighterAST> ourTreeKey = Key.create("lighter.key");
@Nullable
@Override
public LighterAST getLighterAST() {
final IFileElementType contentType = (IFileElementType)getElementType();
assert contentType instanceof ILightStubFileElementType;
LighterAST tree;
if (!isParsed()) {
tree = getUserData(ourTreeKey);
if (tree == null) {
final ILightStubFileElementType<?> type = (ILightStubFileElementType)contentType;
tree = new FCTSBackedLighterAST(getCharTable(), type.parseContentsLight(this));
putUserData(ourTreeKey, tree);
}
}
else {
tree = new TreeBackedLighterAST(this);
}
return tree;
}
@Override
protected void resetCachesOnParsedStateUpdate() {
putUserData(ourTreeKey, null);
super.resetCachesOnParsedStateUpdate();
}
public FileElement(IElementType type, CharSequence text) {
super(type, text);
}
@@ -181,8 +181,8 @@ public class LazyParseableElement extends CompositeElement {
if (rawFirstChild() != null) {
LOG.error("Reentrant parsing?");
}
myText = null;
resetCachesOnParsedStateUpdate();
if (parsedNode == null) return;
super.rawAddChildrenWithoutNotifications((TreeElement)parsedNode);
@@ -199,6 +199,10 @@ public class LazyParseableElement extends CompositeElement {
}
}
protected void resetCachesOnParsedStateUpdate() {
myText = null;
}
@Override
public void rawAddChildrenWithoutNotifications(@NotNull TreeElement first) {
if (myText() != null) {
@@ -0,0 +1,31 @@
/*
* Copyright 2000-2014 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.dupLocator;
import com.intellij.lang.LighterAST;
import com.intellij.lang.LighterASTNode;
import com.intellij.psi.PsiFile;
/**
* Created by Maxim.Mossienko on 10/1/2014.
*/
public interface LightDuplicateProfile {
void process(PsiFile file, Callback callback);
interface Callback {
void process(LighterAST ast, LighterASTNode node, int hash);
}
}
@@ -18,15 +18,18 @@ package com.intellij.dupLocator.index;
import com.intellij.dupLocator.DuplicatesProfile;
import com.intellij.dupLocator.DuplocateVisitor;
import com.intellij.dupLocator.DuplocatorState;
import com.intellij.dupLocator.LightDuplicateProfile;
import com.intellij.dupLocator.treeHash.FragmentsCollector;
import com.intellij.dupLocator.util.PsiFragment;
import com.intellij.lang.Language;
import com.intellij.lang.LighterAST;
import com.intellij.lang.LighterASTNode;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.util.SystemProperties;
import com.intellij.util.indexing.*;
import com.intellij.util.io.DataExternalizer;
@@ -52,6 +55,7 @@ import java.util.Map;
public class DuplicatesIndex extends FileBasedIndexExtension<Integer, TIntArrayList> implements PsiDependentIndex {
static boolean ourEnabled = SystemProperties.getBooleanProperty("idea.enable.duplicates.online.calculation",
isEnabledByDefault());
static boolean ourEnabledLightProfiles = true;
private static boolean isEnabledByDefault() {
Application application = ApplicationManager.getApplication();
@@ -59,7 +63,7 @@ public class DuplicatesIndex extends FileBasedIndexExtension<Integer, TIntArrayL
}
@NonNls public static final ID<Integer, TIntArrayList> NAME = ID.create("DuplicatesIndex");
private static final int myBaseVersion = 10;
private static final int myBaseVersion = 12;
private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() {
@Override
@@ -107,21 +111,31 @@ public class DuplicatesIndex extends FileBasedIndexExtension<Integer, TIntArrayL
@Override
@NotNull
public Map<Integer, TIntArrayList> map(@NotNull final FileContent inputData) {
return ApplicationManager.getApplication().runReadAction(new Computable<Map<Integer, TIntArrayList>>() {
@Override
public Map<Integer, TIntArrayList> compute() {
FileType type = inputData.getFileType();
FileType type = inputData.getFileType();
DuplicatesProfile profile = findDuplicatesProfile(type);
if (profile == null) return Collections.emptyMap();
DuplicatesProfile profile = findDuplicatesProfile(type);
if (profile == null) return Collections.emptyMap();
MyFragmentsCollector collector = new MyFragmentsCollector(profile, ((LanguageFileType)type).getLanguage());
DuplocateVisitor visitor = profile.createVisitor(collector, true);
visitor.visitNode(((FileContentImpl)inputData).getPsiFileAccountingForUnsavedDocument());
PsiFile psiFile = ((FileContentImpl)inputData).getPsiFileAccountingForUnsavedDocument();
return collector.getMap();
}
});
if (profile instanceof LightDuplicateProfile && ourEnabledLightProfiles) {
final THashMap<Integer, TIntArrayList> result = new THashMap<Integer, TIntArrayList>();
((LightDuplicateProfile)profile).process(psiFile, new LightDuplicateProfile.Callback() {
@Override
public void process(LighterAST ast, LighterASTNode node, int hash) {
TIntArrayList list = result.get(hash);
if (list == null) { result.put(hash, list = new TIntArrayList(1)); }
list.add(node.getStartOffset());
}
});
return result;
}
MyFragmentsCollector collector = new MyFragmentsCollector(profile, ((LanguageFileType)type).getLanguage());
DuplocateVisitor visitor = profile.createVisitor(collector, true);
visitor.visitNode(psiFile);
return collector.getMap();
}
};
@@ -135,7 +149,7 @@ public class DuplicatesIndex extends FileBasedIndexExtension<Integer, TIntArrayL
@Override
public int getVersion() {
return myBaseVersion + (ourEnabled ? 0xFF : 0);
return myBaseVersion + (ourEnabled ? 0xFF : 0) + (ourEnabledLightProfiles ? 0x7F : 0);
}
@Override
@@ -3,10 +3,16 @@ package com.intellij.dupLocator.index;
import com.intellij.codeInspection.*;
import com.intellij.dupLocator.DuplicatesProfile;
import com.intellij.dupLocator.DuplocatorState;
import com.intellij.dupLocator.LightDuplicateProfile;
import com.intellij.dupLocator.treeHash.FragmentsCollector;
import com.intellij.dupLocator.util.PsiFragment;
import com.intellij.lang.LighterAST;
import com.intellij.lang.LighterASTNode;
import com.intellij.lang.TreeBackedLighterAST;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWithId;
@@ -35,94 +41,126 @@ public class DuplicatesInspectionBase extends LocalInspectionTool {
final DuplicatesProfile profile = DuplicatesIndex.findDuplicatesProfile(psiFile.getFileType());
if (profile == null) return ProblemDescriptor.EMPTY_ARRAY;
final DuplocatorState state = profile.getDuplocatorState(psiFile.getLanguage());
final SmartList<ProblemDescriptor> descriptors = new SmartList<ProblemDescriptor>();
final Ref<DuplicatedCodeProcessor> myProcessorRef = new Ref<DuplicatedCodeProcessor>();
final TreeMap<Integer, TextRange> reportedRanges = new TreeMap<Integer, TextRange>();
final TIntObjectHashMap<VirtualFile> reportedFiles = new TIntObjectHashMap<VirtualFile>();
final TIntObjectHashMap<PsiElement> reportedPsi = new TIntObjectHashMap<PsiElement>();
final TIntIntHashMap reportedOffsetInOtherFiles = new TIntIntHashMap();
final TIntIntHashMap fragmentSize = new TIntIntHashMap();
if (profile instanceof LightDuplicateProfile && DuplicatesIndex.ourEnabledLightProfiles) {
profile.createVisitor(new FragmentsCollector() {
@Override
public void add(int hash, final int cost, @Nullable final PsiFragment frag) {
if (!DuplicatesIndex.isIndexedFragment(frag, cost, profile, state)) {
return;
((LightDuplicateProfile)profile).process(psiFile, new LightDuplicateProfile.Callback() {
DuplicatedCodeProcessor<LighterASTNode> myProcessor;
@Override
public void process(final LighterAST ast, final LighterASTNode node, int hash) {
class LightDuplicatedCodeProcessor extends DuplicatedCodeProcessor<LighterASTNode> {
LightDuplicatedCodeProcessor(VirtualFile file, Project project) {
super(file, project);
}
@Override
protected TextRange getRangeInElement(LighterASTNode node) {
return null;
}
@Override
protected PsiElement getPsi(LighterASTNode node) {
return ((TreeBackedLighterAST)ast).unwrap(node).getPsi();
}
@Override
protected int getStartOffset(LighterASTNode node) {
return node.getStartOffset();
}
@Override
protected int getEndOffset(LighterASTNode node) {
return node.getEndOffset();
}
}
if (myProcessor == null) {
myProcessor = new LightDuplicatedCodeProcessor(virtualFile, psiFile.getProject());
myProcessorRef.set(myProcessor);
}
myProcessor.process(hash, node);
}
});
} else {
final DuplocatorState state = profile.getDuplocatorState(psiFile.getLanguage());
profile.createVisitor(new FragmentsCollector() {
DuplicatedCodeProcessor<PsiFragment> myProcessor;
@Override
public void add(int hash, final int cost, @Nullable final PsiFragment frag) {
if (!DuplicatesIndex.isIndexedFragment(frag, cost, profile, state)) {
return;
}
ProgressManager.checkCanceled();
FileBasedIndex.getInstance().processValues(DuplicatesIndex.NAME, hash, null, new FileBasedIndex.ValueProcessor<TIntArrayList>() {
final ProjectFileIndex myProjectFileIndex = ProjectFileIndex.SERVICE.getInstance(psiFile.getProject());
@Override
public boolean process(final VirtualFile file, final TIntArrayList list) {
for(int i = 0, len = list.size(); i < len; ++i) {
ProgressManager.checkCanceled();
class OldDuplicatedCodeProcessor extends DuplicatedCodeProcessor<PsiFragment> {
int value = list.getQuick(i);
OldDuplicatedCodeProcessor(VirtualFile file, Project project) {
super(file, project);
}
if (myProjectFileIndex.isInSource(virtualFile) && !myProjectFileIndex.isInSource(file)) return true;
if (!myProjectFileIndex.isInSource(virtualFile) && myProjectFileIndex.isInSource(file)) return true;
final int startOffset = frag.getStartOffset();
final int endOffset = frag.getEndOffset();
if (file.equals(virtualFile) && value >= startOffset && value < endOffset) continue;
PsiElement[] elements = frag.getElements();
PsiElement target = elements[0];
@Override
protected TextRange getRangeInElement(PsiFragment node) {
PsiElement[] elements = node.getElements();
TextRange rangeInElement = null;
if (elements.length > 1) {
PsiElement firstElement = elements[0];
target = firstElement.getParent();
PsiElement lastElement = elements[elements.length - 1];
rangeInElement = new TextRange(
elements[0].getStartOffsetInParent(),
lastElement.getStartOffsetInParent() + lastElement.getTextLength()
);
}
return rangeInElement;
}
Integer fragmentStartOffsetInteger = startOffset;
SortedMap<Integer,TextRange> map = reportedRanges.subMap(fragmentStartOffsetInteger, endOffset);
int newFragmentSize = !map.isEmpty() ? 0:1;
@Override
protected PsiElement getPsi(PsiFragment node) {
PsiElement[] elements = node.getElements();
Iterator<Integer> iterator = map.keySet().iterator();
while(iterator.hasNext()) {
Integer next = iterator.next();
iterator.remove();
reportedFiles.remove(next);
reportedOffsetInOtherFiles.remove(next);
reportedPsi.remove(next);
newFragmentSize += fragmentSize.remove(next);
}
return elements.length > 1 ? elements[0].getParent() : elements[0];
}
reportedRanges.put(fragmentStartOffsetInteger, rangeInElement);
reportedFiles.put(fragmentStartOffsetInteger, file);
reportedOffsetInOtherFiles.put(fragmentStartOffsetInteger, value);
reportedPsi.put(fragmentStartOffsetInteger, target);
fragmentSize.put(fragmentStartOffsetInteger, newFragmentSize);
@Override
protected int getStartOffset(PsiFragment node) {
return node.getStartOffset();
}
return false;
@Override
protected int getEndOffset(PsiFragment node) {
return node.getEndOffset();
}
return true;
}
}, GlobalSearchScope.projectScope(psiFile.getProject()));
if (myProcessor == null) {
myProcessor = new OldDuplicatedCodeProcessor(virtualFile, psiFile.getProject());
myProcessorRef.set(myProcessor);
}
myProcessor.process(hash, frag);
}
}, true).visitNode(psiFile);
}
DuplicatedCodeProcessor<?> processor = myProcessorRef.get();
final SmartList<ProblemDescriptor> descriptors = new SmartList<ProblemDescriptor>();
if (processor != null) {
for(Map.Entry<Integer, TextRange> entry:processor.reportedRanges.entrySet()) {
final Integer offset = entry.getKey();
// todo 3 statements constant
if (processor.fragmentSize.get(offset) < 3) continue;
final VirtualFile file = processor.reportedFiles.get(offset);
String message = "Found duplicated code in " + file.getPath();
PsiElement targetElement = processor.reportedPsi.get(offset);
TextRange rangeInElement = entry.getValue();
final int offsetInOtherFile = processor.reportedOffsetInOtherFiles.get(offset);
LocalQuickFix fix = createNavigateToDupeFix(file, offsetInOtherFile);
ProblemDescriptor descriptor = manager
.createProblemDescriptor(targetElement, rangeInElement, message, ProblemHighlightType.WEAK_WARNING, isOnTheFly, fix);
descriptors.add(descriptor);
}
}, true).visitNode(psiFile);
for(Map.Entry<Integer, TextRange> entry:reportedRanges.entrySet()) {
final Integer offset = entry.getKey();
// todo 3 statements constant
if (fragmentSize.get(offset) < 3) continue;
final VirtualFile file = reportedFiles.get(offset);
String message = "Found duplicated code in " + file.getPath();
PsiElement targetElement = reportedPsi.get(offset);
TextRange rangeInElement = entry.getValue();
final int offsetInOtherFile = reportedOffsetInOtherFiles.get(offset);
LocalQuickFix fix = createNavigateToDupeFix(file, offsetInOtherFile);
ProblemDescriptor descriptor = manager
.createProblemDescriptor(targetElement, rangeInElement, message, ProblemHighlightType.WEAK_WARNING, isOnTheFly, fix);
descriptors.add(descriptor);
}
return descriptors.isEmpty() ? null : descriptors.toArray(new ProblemDescriptor[descriptors.size()]);
@@ -131,4 +169,75 @@ public class DuplicatesInspectionBase extends LocalInspectionTool {
protected LocalQuickFix createNavigateToDupeFix(@NotNull VirtualFile file, int offsetInOtherFile) {
return null;
}
static abstract class DuplicatedCodeProcessor<T> implements FileBasedIndex.ValueProcessor<TIntArrayList> {
final TreeMap<Integer, TextRange> reportedRanges = new TreeMap<Integer, TextRange>();
final TIntObjectHashMap<VirtualFile> reportedFiles = new TIntObjectHashMap<VirtualFile>();
final TIntObjectHashMap<PsiElement> reportedPsi = new TIntObjectHashMap<PsiElement>();
final TIntIntHashMap reportedOffsetInOtherFiles = new TIntIntHashMap();
final TIntIntHashMap fragmentSize = new TIntIntHashMap();
final VirtualFile virtualFile;
final Project project;
final ProjectFileIndex myProjectFileIndex;
T myNode;
DuplicatedCodeProcessor(VirtualFile file, Project project) {
virtualFile = file;
this.project = project;
myProjectFileIndex = ProjectFileIndex.SERVICE.getInstance(project);
}
void process(int hash, T node) {
ProgressManager.checkCanceled();
myNode = node;
FileBasedIndex.getInstance().processValues(DuplicatesIndex.NAME, hash, null, this, GlobalSearchScope.projectScope(project));
}
@Override
public boolean process(VirtualFile file, TIntArrayList list) {
for(int i = 0, len = list.size(); i < len; ++i) {
ProgressManager.checkCanceled();
int value = list.getQuick(i);
if (myProjectFileIndex.isInSource(virtualFile) && !myProjectFileIndex.isInSource(file)) return true;
if (!myProjectFileIndex.isInSource(virtualFile) && myProjectFileIndex.isInSource(file)) return true;
final int startOffset = getStartOffset(myNode);
final int endOffset = getEndOffset(myNode);
if (file.equals(virtualFile) && value >= startOffset && value < endOffset) continue;
PsiElement target = getPsi(myNode);
TextRange rangeInElement = getRangeInElement(myNode);
Integer fragmentStartOffsetInteger = startOffset;
SortedMap<Integer,TextRange> map = reportedRanges.subMap(fragmentStartOffsetInteger, endOffset);
int newFragmentSize = !map.isEmpty() ? 0:1;
Iterator<Integer> iterator = map.keySet().iterator();
while(iterator.hasNext()) {
Integer next = iterator.next();
iterator.remove();
reportedFiles.remove(next);
reportedOffsetInOtherFiles.remove(next);
reportedPsi.remove(next);
newFragmentSize += fragmentSize.remove(next);
}
reportedRanges.put(fragmentStartOffsetInteger, rangeInElement);
reportedFiles.put(fragmentStartOffsetInteger, file);
reportedOffsetInOtherFiles.put(fragmentStartOffsetInteger, value);
reportedPsi.put(fragmentStartOffsetInteger, target);
fragmentSize.put(fragmentStartOffsetInteger, newFragmentSize);
return false;
}
return true;
}
protected abstract TextRange getRangeInElement(T node);
protected abstract PsiElement getPsi(T node);
protected abstract int getStartOffset(T node);
protected abstract int getEndOffset(T node);
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2000-2014 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.dvcs.push;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.annotations.AbstractCollection;
import com.intellij.util.xmlb.annotations.Tag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
@State(name = "Push.Settings", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
public class PushSettings implements PersistentStateComponent<PushSettings.State> {
private State myState = new State();
public static class State {
@Tag("excluded-roots")
@AbstractCollection(surroundWithTag = false, elementTag = "path")
public Set<String> EXCLUDED_ROOTS = ContainerUtil.newHashSet();
}
@Nullable
@Override
public State getState() {
return myState;
}
@Override
public void loadState(State state) {
myState = state;
}
@NotNull
public Set<String> getExcludedRepoRoots() {
return myState.EXCLUDED_ROOTS;
}
public void saveExcludedRepoRoots(@NotNull Set<String> roots) {
myState.EXCLUDED_ROOTS = roots;
}
}
+3
View File
@@ -8,5 +8,8 @@
<!--<keyboard-shortcut first-keystroke="control shift K" keymap="$default"/>-->
<!--</action>-->
</actions>
<extensions defaultExtensionNs="com.intellij">
<projectService serviceImplementation="com.intellij.dvcs.push.PushSettings"/>
</extensions>
</idea-plugin>
@@ -18,8 +18,8 @@ package com.intellij.dvcs.push;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.dvcs.push.ui.*;
import com.intellij.dvcs.repo.Repository;
import com.intellij.dvcs.repo.RepositoryManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
@@ -53,6 +53,8 @@ public class PushController implements Disposable {
@NotNull private final List<PushSupport<?, ?, ?>> myPushSupports;
@NotNull private final PushLog myPushLog;
@NotNull private final VcsPushDialog myDialog;
@NotNull private final PushSettings myExcludedSettings;
@NotNull private final Set<String> myExcludedRepositoryRoots;
private boolean mySingleRepoProject;
private static final int DEFAULT_CHILDREN_PRESENTATION_NUMBER = 20;
private final ExecutorService myExecutorService = Executors.newSingleThreadExecutor();
@@ -64,6 +66,8 @@ public class PushController implements Disposable {
@NotNull VcsPushDialog dialog,
@NotNull List<? extends Repository> preselectedRepositories) {
myProject = project;
myExcludedSettings = ServiceManager.getService(project, PushSettings.class);
myExcludedRepositoryRoots = ContainerUtil.newHashSet(myExcludedSettings.getExcludedRepoRoots());
myPreselectedRepositories = preselectedRepositories;
myPushSupports = getAffectedSupports(myProject);
mySingleRepoProject = isSingleRepoProject(myPushSupports);
@@ -125,7 +129,8 @@ public class PushController implements Disposable {
Map<RepositoryNode, MyRepoModel> others = ContainerUtil.newLinkedHashMap();
for (Map.Entry<RepositoryNode, MyRepoModel> entry : myView2Model.entrySet()) {
MyRepoModel model = entry.getValue();
if (myPreselectedRepositories.contains(model.getRepository())) {
Repository repository = model.getRepository();
if (preselectByUser(repository)) {
priorityLoading.put(entry.getKey(), model);
}
else if (model.getSupport().shouldRequestIncomingChangesForNotCheckedRepositories()) {
@@ -188,6 +193,7 @@ public class PushController implements Disposable {
@Override
public void onTargetChanged(T newTarget) {
repoNode.setChecked(true);
myExcludedRepositoryRoots.remove(model.getRepository().getRoot().getPath());
model.setTarget(newTarget);
model.clearErrors();
loadCommits(model, repoNode, false);
@@ -196,9 +202,14 @@ public class PushController implements Disposable {
@Override
public void onSelectionChanged(boolean isSelected) {
myDialog.enableOkActions(isPushAllowed());
if (isSelected && !model.hasCommitInfo() && !model.getSupport().shouldRequestIncomingChangesForNotCheckedRepositories()) {
//download incoming if was not loaded before and marked as selected
loadCommits(model, repoNode, false);
if (isSelected) {
boolean forceLoad = myExcludedRepositoryRoots.remove(model.getRepository().getRoot().getPath());
if (!model.hasCommitInfo() && (forceLoad || !model.getSupport().shouldRequestIncomingChangesForNotCheckedRepositories())) {
loadCommits(model, repoNode, false);
}
}
else {
myExcludedRepositoryRoots.add(model.getRepository().getRoot().getPath());
}
}
});
@@ -235,9 +246,54 @@ public class PushController implements Disposable {
public boolean isPushAllowed() {
JTree tree = myPushLog.getTree();
return !tree.isEditing() && !getSelectedRepoNode().isEmpty() && allNodesAreLoaded(myView2Model.keySet());
return !tree.isEditing() &&
ContainerUtil.exists(myPushSupports, new Condition<PushSupport<?, ?, ?>>() {
@Override
public boolean value(PushSupport<?, ?, ?> support) {
return isPushAllowed(support);
}
});
}
private boolean isPushAllowed(@NotNull PushSupport<?, ?, ?> pushSupport) {
Collection<RepositoryNode> nodes = getNodesForSupport(pushSupport);
if (pushSupport.getRepositoryManager().isSyncEnabled()) {
return hasSomethingToPush(nodes) || (hasCheckedNode(nodes) && allNodesAreLoaded(nodes));
}
return hasSomethingToPush(nodes) || (hasCheckedNode(nodes));
}
private boolean hasSomethingToPush(Collection<RepositoryNode> nodes) {
return ContainerUtil.exists(nodes, new Condition<RepositoryNode>() {
@Override
public boolean value(@NotNull RepositoryNode node) {
PushTarget target = myView2Model.get(node).getTarget();
//if node is selected target should not be null
return (node.isChecked() || node.isLoading()) && target != null && target.hasSomethingToPush();
}
});
}
private static boolean hasCheckedNode(@NotNull Collection<RepositoryNode> nodes) {
return ContainerUtil.exists(nodes, new Condition<RepositoryNode>() {
@Override
public boolean value(@NotNull RepositoryNode node) {
return node.isChecked();
}
});
}
@NotNull
private Collection<RepositoryNode> getNodesForSupport(final PushSupport<?, ?, ?> support) {
return ContainerUtil.mapNotNull(myView2Model.entrySet(), new Function<Map.Entry<RepositoryNode, MyRepoModel>, RepositoryNode>() {
@Override
public RepositoryNode fun(Map.Entry<RepositoryNode, MyRepoModel> entry) {
return support.equals(entry.getValue().getSupport()) ? entry.getKey() : null;
}
});
}
private static boolean allNodesAreLoaded(@NotNull Collection<RepositoryNode> nodes) {
return !ContainerUtil.exists(nodes, new Condition<RepositoryNode>() {
@Override
@@ -294,8 +350,8 @@ public class PushController implements Disposable {
}
else {
List<? extends VcsFullCommitDetails> commits = outgoing.getCommits();
shouldBeSelected = shouldSelectInitially(target, repository, model.getSupport().getRepositoryManager(), !commits.isEmpty());
model.setLoadedCommits(commits);
shouldBeSelected = shouldSelect(model);
myPushLog.setChildren(node,
getPresentationForCommits(PushController.this.myProject, model.getLoadedCommits(),
model.getNumberOfShownCommits()));
@@ -315,19 +371,24 @@ public class PushController implements Disposable {
node.startLoading(myPushLog.getTree(), myExecutorService.submit(task, result));
}
private boolean shouldSelectInitially(@NotNull PushTarget target, @NotNull Repository repository,
@NotNull RepositoryManager repositoryManager, boolean hasCommits) {
boolean shouldBeSelected;
if (mySingleRepoProject) {
shouldBeSelected = true;
}
else if (repositoryManager.isSyncEnabled()) {
shouldBeSelected = hasCommits || target.hasSomethingToPush();
}
else {
shouldBeSelected = (hasCommits || target.hasSomethingToPush()) && myPreselectedRepositories.contains(repository);
}
return shouldBeSelected;
private boolean shouldSelect(@NotNull MyRepoModel model) {
if (mySingleRepoProject) return true;
Repository repository = model.getRepository();
return hasCommitsToPush(model) && (preselectByUser(repository) || notExcludedByUser(repository));
}
private boolean notExcludedByUser(@NotNull Repository repository) {
return !myExcludedRepositoryRoots.contains(repository.getRoot().getPath());
}
private boolean preselectByUser(@NotNull Repository repository) {
return myPreselectedRepositories.contains(repository);
}
private static boolean hasCommitsToPush(@NotNull MyRepoModel model) {
PushTarget target = model.getTarget();
assert target != null;
return (!model.getLoadedCommits().isEmpty() || target.hasSomethingToPush());
}
public PushLog getPushPanelLog() {
@@ -338,6 +399,7 @@ public class PushController implements Disposable {
Task.Backgroundable task = new Task.Backgroundable(myProject, "Pushing...", false) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
myExcludedSettings.saveExcludedRepoRoots(myExcludedRepositoryRoots);
for (PushSupport support : myPushSupports) {
doPush(support, force);
}
@@ -69,6 +69,7 @@ class LoadingIcon extends JBImageIcon {
}
public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h) {
if (myNode instanceof RepositoryNode && !((RepositoryNode)myNode).isLoading()) return false;
if ((flags & (FRAMEBITS | ALLBITS)) != 0) {
TreeNode[] pathToRoot = myModel.getPathToRoot(myNode);
if (pathToRoot != null) {
@@ -155,6 +155,7 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode,
public void stopLoading() {
myLoading.set(false);
myLoadingIcon.setImageObserver(null);
}
public boolean isLoading() {
@@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.OptionAction;
import com.intellij.openapi.ui.ValidationInfo;
import net.miginfocom.swing.MigLayout;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -81,6 +82,18 @@ public class VcsPushDialog extends DialogWrapper {
return ID;
}
@Nullable
@Override
protected ValidationInfo doValidate() {
enableOkActions(myController.isPushAllowed());
return null;
}
@Override
protected boolean postponeValidation() {
return false;
}
@Override
@NotNull
protected Action[] createActions() {
@@ -16,6 +16,7 @@
package com.intellij.ide.ui;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.WelcomeWizardUtil;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
@@ -128,6 +129,9 @@ public class UISettings extends SimpleModificationTracker implements PersistentS
public UISettings() {
tweakPlatformDefaults();
setSystemFontFaceAndSize();
Boolean scrollToSource = WelcomeWizardUtil.getAutoScrollToSource();
if (scrollToSource != null) DEFAULT_AUTOSCROLL_TO_SOURCE = scrollToSource;
}
private void tweakPlatformDefaults() {
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

@@ -164,6 +164,7 @@ public class StdArrangementTokens {
@NotNull public static final ArrangementSettingsToken PROPERTY = invertible("PROPERTY", StdArrangementTokenType.ENTRY_TYPE);
@NotNull public static final ArrangementSettingsToken EVENT_HANDLER = invertible("EVENT_HANDLER", StdArrangementTokenType.ENTRY_TYPE);
@NotNull public static final ArrangementSettingsToken STATIC_INIT = invertible("STATIC_INIT", StdArrangementTokenType.ENTRY_TYPE);
@NotNull public static final ArrangementSettingsToken INIT_BLOCK = invertible("INITIALIZER BLOCK", StdArrangementTokenType.ENTRY_TYPE);
@NotNull public static final ArrangementSettingsToken NAMESPACE = invertible("NAMESPACE", StdArrangementTokenType.ENTRY_TYPE);
@NotNull public static final ArrangementSettingsToken TRAIT = invertible("TRAIT", StdArrangementTokenType.ENTRY_TYPE);
@@ -45,6 +45,7 @@ public class Descriptor {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.Descriptor");
private final ScopeToolState myState;
private final InspectionProfileImpl myInspectionProfile;
private final String myScopeName;
public Descriptor(@NotNull ScopeToolState state, @NotNull InspectionProfileImpl inspectionProfile, @NotNull Project project) {
myState = state;
@@ -54,6 +55,7 @@ public class Descriptor {
final String[] groupPath = tool.getGroupPath();
myGroup = groupPath.length == 0 ? new String[]{InspectionProfileEntry.GENERAL_GROUP_NAME} : groupPath;
myKey = HighlightDisplayKey.find(tool.getShortName());
myScopeName = state.getScopeName();
myScope = state.getScope(project);
myLevel = inspectionProfile.getErrorLevel(myKey, myScope, project);
myEnabled = inspectionProfile.isToolEnabled(myKey, myScope, project);
@@ -137,6 +139,11 @@ public class Descriptor {
return myGroup;
}
@NotNull
public String getScopeName() {
return myScopeName;
}
@Nullable
public NamedScope getScope() {
return myScope;

Some files were not shown because too many files have changed in this diff Show More