From bae0c9cd0f7a5d52792b255f3e5ef6af02d3cb40 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 9 Mar 2012 12:19:20 +0400 Subject: [PATCH 01/44] IDEA-79269 GitUpdater: fix the way to understand that update is not needed git diff is symmetrical, i.e. git diff .. will give the difference between branches, no matter which branch "introduced" the commit. Here we need git log .., because we need to know if there were any commits in the remote branch, i.e. that update is needed. --- .../git4idea/src/git4idea/update/GitUpdater.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/git4idea/src/git4idea/update/GitUpdater.java b/plugins/git4idea/src/git4idea/update/GitUpdater.java index a70dd29aa586..33e3cd13d546 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdater.java @@ -24,9 +24,10 @@ import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitBranch; import git4idea.GitRevisionNumber; -import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.branch.GitBranchPair; +import git4idea.commands.GitCommand; +import git4idea.commands.GitSimpleHandler; import git4idea.config.GitConfigUtil; import git4idea.config.GitVcsSettings; import git4idea.merge.MergeChangeCollector; @@ -132,7 +133,7 @@ public abstract class GitUpdater { GitBranch dest = gitBranchPair.getDest(); assert dest != null; String remoteBranch = dest.getName(); - if (! hasRemotelyChangedPaths(currentBranch, remoteBranch)) { + if (! hasRemoteChanges(currentBranch, remoteBranch)) { LOG.info("isSaveNeeded No remote changes, save is not needed"); return false; } @@ -159,7 +160,11 @@ public abstract class GitUpdater { } } - protected boolean hasRemotelyChangedPaths(@NotNull String currentBranch, @NotNull String remoteBranch) throws VcsException { - return !GitUtil.getPathsDiffBetweenRefs(currentBranch, remoteBranch, myProject, myRoot).isEmpty(); + protected boolean hasRemoteChanges(@NotNull String currentBranch, @NotNull String remoteBranch) throws VcsException { + GitSimpleHandler handler = new GitSimpleHandler(myProject, myRoot, GitCommand.LOG); + handler.setNoSSH(true); + handler.addParameters(currentBranch + ".." + remoteBranch); + String output = handler.run(); + return output != null && !output.isEmpty(); } } From a3b93425f670c0724505a9b5e492682442b2606c Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 9 Mar 2012 13:09:18 +0400 Subject: [PATCH 02/44] IDEA-77873 Fetch only the tracked branch of the current branch on Update Project Make GitFetcher work in 2 modes: - "fetch all": for the "Fetch" action and for "Pull" over HTTP (it is not needed for the latter, but it's a relatively rare case, so for easier development (not to supply branches to be fetcher to GitFetcher) fetch all). - "fetch only current branch": for UpdateProcess, i.e. for "Update Project" and "Push"). Support fetching a specific branch in GitHttpAdapter. Make refs/heads/ conversion, because JGit need the full branch name. GitUpdateProcess: perform checks that update is possible before fetching. Reasons: - Not to fail in GitFetcher when getting the current branch and the tracked branch. - Performance gain: if update is not possible, fetch won't be performed. --- .../src/git4idea/actions/GitFetch.java | 2 +- .../src/git4idea/actions/GitPull.java | 2 +- .../src/git4idea/branch/GitBranchUtil.java | 44 ++++++++++++ .../src/git4idea/jgit/GitHttpAdapter.java | 17 ++++- .../src/git4idea/update/GitFetcher.java | 68 +++++++++++++++++-- .../src/git4idea/update/GitUpdateProcess.java | 11 +-- 6 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 plugins/git4idea/src/git4idea/branch/GitBranchUtil.java diff --git a/plugins/git4idea/src/git4idea/actions/GitFetch.java b/plugins/git4idea/src/git4idea/actions/GitFetch.java index df93cda9841a..07d041f2f08e 100644 --- a/plugins/git4idea/src/git4idea/actions/GitFetch.java +++ b/plugins/git4idea/src/git4idea/actions/GitFetch.java @@ -46,7 +46,7 @@ public class GitFetch extends GitRepositoryAction { GitVcs.runInBackground(new Task.Backgroundable(project, "Fetching...", false) { @Override public void run(@NotNull ProgressIndicator indicator) { - new GitFetcher(project, indicator).fetchRootsAndNotify(gitRoots, null, true); + new GitFetcher(project, indicator, true).fetchRootsAndNotify(gitRoots, null, true); } }); } diff --git a/plugins/git4idea/src/git4idea/actions/GitPull.java b/plugins/git4idea/src/git4idea/actions/GitPull.java index 8533801b1492..0d2cf7c1fe4b 100644 --- a/plugins/git4idea/src/git4idea/actions/GitPull.java +++ b/plugins/git4idea/src/git4idea/actions/GitPull.java @@ -83,7 +83,7 @@ public class GitPull extends GitRepositoryAction { } if (GitHttpAdapter.shouldUseJGit(url)) { - boolean fetchSuccessful = new GitFetcher(project, indicator).fetchRootsAndNotify(gitRoots, "Pull failed", false); + boolean fetchSuccessful = new GitFetcher(project, indicator, true).fetchRootsAndNotify(gitRoots, "Pull failed", false); if (!fetchSuccessful) { return; } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java new file mode 100644 index 000000000000..d93c65550e76 --- /dev/null +++ b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.branch; + +import git4idea.GitBranch; +import git4idea.repo.GitBranchTrackInfo; +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Kirill Likhodedov + */ +public class GitBranchUtil { + + private GitBranchUtil() {} + + /** + * Returns the tracking information about the given branch in the given repository, + * or null if there is no such information (i.e. if the branch doesn't have a tracking branch). + */ + @Nullable + public static GitBranchTrackInfo getTrackInfoForBranch(@NotNull GitRepository repository, @NotNull GitBranch branch) { + for (GitBranchTrackInfo trackInfo : repository.getConfig().getBranchTrackInfos()) { + if (trackInfo.getBranch().equals(branch.getName())) { + return trackInfo; + } + } + return null; + } +} diff --git a/plugins/git4idea/src/git4idea/jgit/GitHttpAdapter.java b/plugins/git4idea/src/git4idea/jgit/GitHttpAdapter.java index 6c121759108e..fa262695f3dd 100644 --- a/plugins/git4idea/src/git4idea/jgit/GitHttpAdapter.java +++ b/plugins/git4idea/src/git4idea/jgit/GitHttpAdapter.java @@ -102,12 +102,25 @@ public final class GitHttpAdapter { * Asks username and password if needed. */ @NotNull - public static GitFetchResult fetch(@NotNull final GitRepository repository, @NotNull final GitRemote remote, @NotNull String remoteUrl) { + public static GitFetchResult fetch(@NotNull final GitRepository repository, @NotNull final GitRemote remote, + @NotNull String remoteUrl, @Nullable String remoteBranch) { GitFetchResult.Type resultType; try { final Git git = convertToGit(repository); final GitHttpCredentialsProvider provider = new GitHttpCredentialsProvider(repository.getProject(), remoteUrl); - GeneralResult result = callWithAuthRetry(new GitHttpRemoteCommand.Fetch(git, provider, remoteUrl, convertRefSpecs(remote.getFetchRefSpecs())), + + List specs; + if (remoteBranch == null) { + specs = remote.getFetchRefSpecs(); + } + else { + if (!remoteBranch.startsWith(GitBranch.REFS_HEADS_PREFIX)) { + remoteBranch = GitBranch.REFS_HEADS_PREFIX + remoteBranch; + } + specs = Collections.singletonList(remoteBranch); + } + + GeneralResult result = callWithAuthRetry(new GitHttpRemoteCommand.Fetch(git, provider, remoteUrl, convertRefSpecs(specs)), repository.getProject()); resultType = convertToFetchResultType(result); } catch (IOException e) { diff --git a/plugins/git4idea/src/git4idea/update/GitFetcher.java b/plugins/git4idea/src/git4idea/update/GitFetcher.java index b498934a9213..2eb080ef59de 100644 --- a/plugins/git4idea/src/git4idea/update/GitFetcher.java +++ b/plugins/git4idea/src/git4idea/update/GitFetcher.java @@ -23,11 +23,14 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; +import git4idea.GitBranch; import git4idea.GitVcs; import git4idea.Notificator; +import git4idea.branch.GitBranchUtil; import git4idea.commands.*; import git4idea.config.GitVersionSpecialty; import git4idea.jgit.GitHttpAdapter; +import git4idea.repo.GitBranchTrackInfo; import git4idea.repo.GitRemote; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; @@ -53,13 +56,19 @@ public class GitFetcher { private final Project myProject; private final GitRepositoryManager myRepositoryManager; private final ProgressIndicator myProgressIndicator; + private final boolean myFetchAll; private final GitVcs myVcs; private final Collection myErrors = new ArrayList(); - public GitFetcher(@NotNull Project project, @NotNull ProgressIndicator progressIndicator) { + /** + * @param fetchAll Pass {@code true} to fetch all remotes and all branches (like {@code git fetch} without parameters does). + * Pass {@code false} to fetch only the tracked branch of the current branch. + */ + public GitFetcher(@NotNull Project project, @NotNull ProgressIndicator progressIndicator, boolean fetchAll) { myProject = project; myProgressIndicator = progressIndicator; + myFetchAll = fetchAll; myRepositoryManager = GitRepositoryManager.getInstance(project); myVcs = GitVcs.getInstance(project); } @@ -74,22 +83,66 @@ public class GitFetcher { // TODO need to have a fair compound result here GitFetchResult fetchResult = GitFetchResult.success(); + if (myFetchAll) { + fetchResult = fetchAll(root, repository, fetchResult); + } + else { + return fetchCurrentBranch(root, repository); + } + + repository.update(GitRepository.TrackedTopic.BRANCHES); + return fetchResult; + } + + @NotNull + private GitFetchResult fetchCurrentBranch(@NotNull VirtualFile root, @NotNull GitRepository repository) { + GitBranch currentBranch = repository.getCurrentBranch(); + if (currentBranch == null) { + String message = "Current branch can't be null here. \nRepository: " + repository; + LOG.error(message); + return GitFetchResult.error(new Exception(message)); + } + GitBranchTrackInfo trackInfo = GitBranchUtil.getTrackInfoForBranch(repository, currentBranch); + if (trackInfo == null) { + String message = "Tracked info is null for branch " + currentBranch + "\n Repository: " + repository; + LOG.error(message); + return GitFetchResult.error(new Exception(message)); + } + + GitRemote remote = trackInfo.getRemote(); + String url = remote.getFirstUrl(); + if (url == null) { + String message = "URL is null for remote " + remote.getName(); + LOG.error(message); + return GitFetchResult.error(new Exception(message)); + } + + String remoteBranch = trackInfo.getRemoteBranch(); + if (GitHttpAdapter.shouldUseJGit(url)) { + return GitHttpAdapter.fetch(repository, remote, url, remoteBranch); + } + return fetchNatively(root, remote, remoteBranch); + } + + @NotNull + private GitFetchResult fetchAll(@NotNull VirtualFile root, @NotNull GitRepository repository, @NotNull GitFetchResult fetchResult) { for (GitRemote remote : repository.getRemotes()) { String url = remote.getFirstUrl(); if (url == null) { + LOG.error("URL is null for remote " + remote.getName()); continue; } if (GitHttpAdapter.shouldUseJGit(url)) { - GitFetchResult res = GitHttpAdapter.fetch(repository, remote, url); + GitFetchResult res = GitHttpAdapter.fetch(repository, remote, url, null); res.addPruneInfo(fetchResult.getPrunedRefs()); fetchResult = res; myErrors.addAll(fetchResult.getErrors()); if (!fetchResult.isSuccess()) { break; } - } + } else { - GitFetchResult res = fetchNatively(root, remote); + GitFetchResult res = fetchNatively(root, remote, null); res.addPruneInfo(fetchResult.getPrunedRefs()); fetchResult = res; if (!fetchResult.isSuccess()) { @@ -97,17 +150,18 @@ public class GitFetcher { } } } - - repository.update(GitRepository.TrackedTopic.BRANCHES); return fetchResult; } - private GitFetchResult fetchNatively(@NotNull VirtualFile root, @NotNull GitRemote remote) { + private GitFetchResult fetchNatively(@NotNull VirtualFile root, @NotNull GitRemote remote, @Nullable String branch) { final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(myProject, root, GitCommand.FETCH); if (GitVersionSpecialty.SUPPORTS_FETCH_PRUNE.existsIn(myVcs.getVersion())) { h.addParameters("--prune"); } h.addParameters(remote.getName()); + if (branch != null) { + h.addParameters(branch); + } final GitTask fetchTask = new GitTask(myProject, h, "Fetching..."); fetchTask.setProgressIndicator(myProgressIndicator); fetchTask.setProgressAnalyzer(new GitStandardProgressAnalyzer()); diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java index 848ae5f14802..a270dbfe7e3c 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java @@ -108,6 +108,11 @@ public class GitUpdateProcess { String oldText = myProgressIndicator.getText(); myProgressIndicator.setText("Updating..."); + // check if update is possible + if (checkRebaseInProgress() || isMergeInProgress() || areUnmergedFiles() || !checkTrackedBranchesConfigured()) { + return false; + } + if (!fetchAndNotify()) { return false; } @@ -125,10 +130,6 @@ public class GitUpdateProcess { private boolean updateImpl(UpdateMethod updateMethod, ContinuationContext context) { // define updaters for roots - // check if update is possible - if (checkRebaseInProgress() || isMergeInProgress() || areUnmergedFiles()) return false; - if (!checkTrackedBranchesConfigured()) return false; - try { for (VirtualFile root : myRoots) { final GitUpdater updater; @@ -222,7 +223,7 @@ public class GitUpdateProcess { // fetch all roots. If an error happens, return false and notify about errors. private boolean fetchAndNotify() { - return new GitFetcher(myProject, myProgressIndicator).fetchRootsAndNotify(myRoots, "Update failed", false); + return new GitFetcher(myProject, myProgressIndicator, false).fetchRootsAndNotify(myRoots, "Update failed", false); } public Map getTrackedBranches() { From b5bf6ea6ee864ab0f10551a2630fe16f6d0a55bf Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 9 Mar 2012 13:12:27 +0400 Subject: [PATCH 03/44] Skip warnings in the pregenerated equals and hashcode: values nullability may change in the future. --- plugins/git4idea/src/git4idea/repo/GitBranchTrackInfo.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/git4idea/src/git4idea/repo/GitBranchTrackInfo.java b/plugins/git4idea/src/git4idea/repo/GitBranchTrackInfo.java index f7b79d1e6345..bc70772c27e5 100644 --- a/plugins/git4idea/src/git4idea/repo/GitBranchTrackInfo.java +++ b/plugins/git4idea/src/git4idea/repo/GitBranchTrackInfo.java @@ -64,6 +64,7 @@ public class GitBranchTrackInfo { return String.format("%s %s %s %b", myBranch, myRemote, myRemoteBranch, myMerge); } + @SuppressWarnings("ConstantConditions") @Override public boolean equals(Object o) { @@ -80,6 +81,7 @@ public class GitBranchTrackInfo { return true; } + @SuppressWarnings("ConstantConditions") @Override public int hashCode() { int result = myBranch != null ? myBranch.hashCode() : 0; From 5548992b4542b6e72e686ba1cc5bba97236236da Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 9 Mar 2012 10:42:41 +0100 Subject: [PATCH 04/44] fix tests --- .../src/com/intellij/ide/util/FileStructurePopup.java | 9 +++++++-- .../com/intellij/ide/util/treeView/AbstractTreeUi.java | 4 +--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index b61df45a94f2..5a9529260e5b 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -593,7 +593,7 @@ public class FileStructurePopup implements Disposable { myFilteringStructure.rebuild(); final Object sel = selection; - ApplicationManager.getApplication().invokeLater(new Runnable() { + final Runnable runnable = new Runnable() { public void run() { final AccessToken token = ApplicationManager.getApplication().acquireReadActionLock(); try { @@ -610,7 +610,12 @@ public class FileStructurePopup implements Disposable { token.finish(); } } - }); + }; + if (ApplicationManager.getApplication().isUnitTestMode()) { + runnable.run(); + } else { + ApplicationManager.getApplication().invokeLater(runnable); + } } }); chkFilter.setFocusable(false); diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index 5af6d5c43eb9..36eb0ce043ca 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -4067,7 +4067,7 @@ public class AbstractTreeUi { return preselectedRow; } - private void expandAllWithoutRecursion(@Nullable final Runnable onDone) { + public void expandAllWithoutRecursion(@Nullable final Runnable onDone) { final JTree tree = getTree(); int myCurrentRow = 0; if (tree.getRowCount() > 0) { @@ -4083,8 +4083,6 @@ public class AbstractTreeUi { } public void expandAll(@Nullable final Runnable onDone) { - if (isPassthroughMode()) expandAllWithoutRecursion(onDone); - final JTree tree = getTree(); if (tree.getRowCount() > 0) { final int expandRecursionDepth = Math.max(2, Registry.intValue("ide.tree.expandRecursionDepth")); From 54b88bcb8c6c97abd49fbd7cc0bbe1624446bb9f Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 14:57:38 +0400 Subject: [PATCH 05/44] IDEA-69336 Make ad in completion popup in Expression Evaluation Dialog --- .../debugger/engine/evaluation/DefaultCodeFragmentFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java index 99a93876bf4e..bec0848383fb 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java @@ -81,7 +81,7 @@ public class DefaultCodeFragmentFactory extends CodeFragmentFactory { if (parameters.getInvocationCount() <= 1 && JavaCompletionUtil.containsMethodCalls(expression)) { final CompletionService service = CompletionService.getCompletionService(); - if (service.getAdvertisementText() == null && parameters.getInvocationCount() == 1) { + if (service.getAdvertisementText() == null && parameters.getInvocationCount() < 2) { service.setAdvertisementText("Invoke completion once more to see runtime type variants"); } return null; From c4ed6f3022450d0aa29965dc35a89879c19c0af7 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 15:16:40 +0400 Subject: [PATCH 06/44] IDEA-68584 Completion should detect return type and autocast in some cases --- .../completion/JavaCompletionUtil.java | 157 +++++++++--------- ...erenceExpressionCompletionContributor.java | 23 +-- .../scope/JavaCompletionProcessor.java | 2 +- .../codeInsight/lookup/PsiTypeLookupItem.java | 1 + .../completion/normal/CastVisually.java | 14 ++ .../completion/NormalCompletionTest.groovy | 8 + .../completion/GroovyNoVariantsDelegator.java | 2 +- 7 files changed, 109 insertions(+), 98 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normal/CastVisually.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 3c5b21d43b46..12adae0a1fcd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -30,28 +30,23 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.NullableLazyKey; -import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.PsiElementPattern; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.codeStyle.*; -import com.intellij.psi.filters.AndFilter; -import com.intellij.psi.filters.ClassFilter; import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.filters.element.ExcludeDeclaredFilter; -import com.intellij.psi.filters.element.ExcludeSillyAssignment; import com.intellij.psi.html.HtmlTag; +import com.intellij.psi.impl.FakePsiElement; +import com.intellij.psi.impl.light.LightVariableBuilder; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.impl.source.PsiImmediateClassType; import com.intellij.psi.javadoc.PsiDocToken; import com.intellij.psi.scope.BaseScopeProcessor; -import com.intellij.psi.scope.ElementClassFilter; import com.intellij.psi.scope.ElementClassHint; import com.intellij.psi.scope.NameHint; +import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiFormatUtil; @@ -78,13 +73,7 @@ public class JavaCompletionUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.JavaCompletionUtil"); public static final Key> DYNAMIC_TYPE_EVALUATOR = Key.create("DYNAMIC_TYPE_EVALUATOR"); - static final Key QUALIFIER_TYPE_ATTR = Key.create("qualifierType"); // SmartPsiElementPointer to PsiType of "qualifier" - @NonNls - public static final String GET_PREFIX = "get"; - @NonNls - public static final String SET_PREFIX = "set"; - @NonNls - public static final String IS_PREFIX = "is"; + private static final Key QUALIFIER_TYPE_ATTR = Key.create("qualifierType"); // SmartPsiElementPointer to PsiType of "qualifier" public static final OffsetKey LPAREN_OFFSET = OffsetKey.create("lparen"); public static final OffsetKey RPAREN_OFFSET = OffsetKey.create("rparen"); public static final OffsetKey ARG_LIST_END_OFFSET = OffsetKey.create("argListEnd"); @@ -435,20 +424,26 @@ public class JavaCompletionUtil { boolean checkInitialized = parameters.getInvocationCount() <= 1 && call != null && PsiKeyword.SUPER.equals(call.getMethodExpression().getText()); final JavaCompletionProcessor processor = new JavaCompletionProcessor(element, elementFilter, checkAccess, checkInitialized, filterStaticAfterInstance, nameCondition); + final PsiType plainQualifier = processor.getQualifierType(); + PsiType qualifierType = plainQualifier; + + PsiType runtimeQualifier = getQualifierCastType(javaReference, parameters); + if (runtimeQualifier != null) { + javaReference = (PsiReferenceExpression) JavaPsiFacade.getElementFactory(element.getProject()).createExpressionFromText("xxx.xxx", createContextWithXxxVariable(element, runtimeQualifier)); + qualifierType = runtimeQualifier; + } + javaReference.processVariants(processor); - final Collection plainResults = processor.getResults(); - final PsiType qualifierType = processor.getQualifierType(); - PsiType castedQualifierType = addQualifierCastingVariants(javaReference, processor, set, parameters); - - boolean mayHighlight = qualifierType != null && (castedQualifierType == null || castedQualifierType.equals(qualifierType) || !qualifierType.isAssignableFrom(castedQualifierType)); + final PsiTypeLookupItem castItem = runtimeQualifier == null ? null : PsiTypeLookupItem.createLookupItem(runtimeQualifier, (PsiReferenceExpression)javaReference); final boolean pkgContext = inSomePackage(element); final Set mentioned = new THashSet(); - for (CompletionElement completionElement : plainResults) { - LookupElement item = createLookupElement(completionElement, qualifierType); + for (CompletionElement completionElement : processor.getResults()) { + LookupElement item = createLookupElement(completionElement); if (item != null) { + item.putUserData(QUALIFIER_TYPE_ATTR, qualifierType); final Object o = item.getObject(); if (o instanceof PsiClass && !isSourceLevelAccessible(element, (PsiClass)o, pkgContext)) { continue; @@ -459,7 +454,7 @@ public class JavaCompletionUtil { } mentioned.add((PsiMember)o); } - set.add(mayHighlight ? highlightIfNeeded(qualifierType, item, o) : item); + set.add(highlightIfNeeded(qualifierType, castQualifier(item, castItem, plainQualifier), o)); } } @@ -479,68 +474,63 @@ public class JavaCompletionUtil { } @Nullable - private static PsiType addQualifierCastingVariants(PsiJavaReference javaReference, JavaCompletionProcessor processor, THashSet set, CompletionParameters parameters) { + private static PsiType getQualifierCastType(PsiJavaReference javaReference, CompletionParameters parameters) { if (javaReference instanceof PsiReferenceExpression) { final PsiReferenceExpression refExpr = (PsiReferenceExpression)javaReference; final PsiExpression qualifier = refExpr.getQualifierExpression(); if (qualifier != null) { final Project project = qualifier.getProject(); - final PairFunction evaluator = refExpr.getContainingFile().getCopyableUserData(DYNAMIC_TYPE_EVALUATOR); - PsiReferenceExpression context = refExpr; PsiType type = null; + final PairFunction evaluator = refExpr.getContainingFile().getCopyableUserData(DYNAMIC_TYPE_EVALUATOR); if (evaluator != null) { type = evaluator.fun(qualifier, parameters); - context = null; } if (type == null) { type = GuessManager.getInstance(project).getControlFlowExpressionType(qualifier); - context = refExpr; - } - if (type != null) { - processor.clear(); - - return addQualifierCastingVariants(processor, refExpr, type, set, context); } + return type; } } return null; } - private static PsiType addQualifierCastingVariants(JavaCompletionProcessor processor, PsiReferenceExpression refExpr, - PsiType castTo, - THashSet set, final PsiReferenceExpression context) { - Project project = refExpr.getProject(); - - PsiExpression qualifier = refExpr.getQualifierExpression(); - assert qualifier != null; - final String newText = "((" + castTo.getCanonicalText() + ") " + qualifier.getText() + ")." + refExpr.getReferenceName(); - final PsiExpression newRef = JavaPsiFacade.getElementFactory(project).createExpressionFromText(newText, context); - ((PsiReferenceExpression)newRef).processVariants(processor); - - final LookupElement castItem = PsiTypeLookupItem.createLookupItem(castTo, refExpr); - - for (CompletionElement completionElement : processor.getResults()) { - final LookupElement item = createLookupElement(completionElement, castTo); - if (item != null) { - LookupElement item1 = castQualifier(project, item, castItem); - set.add(highlightIfNeeded(castTo, item1, item1.getObject())); + @NotNull + private static LookupElement castQualifier(@NotNull LookupElement item, + @Nullable final PsiTypeLookupItem castTypeItem, + @Nullable PsiType plainQualifier) { + if (castTypeItem == null) { + return item; + } + if (plainQualifier != null) { + Object o = item.getObject(); + if (containsMember(plainQualifier, o)) { + if (!(o instanceof PsiMethod)) { + return item; + } + PsiType castType = castTypeItem.getPsiType(); + if (plainQualifier instanceof PsiClassType && castType instanceof PsiClassType) { + PsiMethod method = (PsiMethod)o; + PsiSubstitutor plainSub = ((PsiClassType)plainQualifier).resolveGenerics().getSubstitutor(); + PsiSubstitutor castSub = ((PsiClassType)castType).resolveGenerics().getSubstitutor(); + if (method.getSignature(plainSub).equals(method.getSignature(castSub)) && + plainSub.substitute(method.getReturnType()).equals(castSub.substitute(method.getReturnType()))) { + return item; + } + } } } - return castTo; - } - private static LookupElementDecorator castQualifier(final Project project, LookupElement item, final LookupElement to) { return LookupElementDecorator.withInsertHandler(item, new InsertHandlerDecorator() { public void handleInsert(InsertionContext context, LookupElementDecorator item) { final Document document = context.getEditor().getDocument(); - PsiDocumentManager.getInstance(project).commitDocument(document); + context.commitDocument(); final PsiFile file = context.getFile(); final PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset(file, context.getStartOffset(), PsiJavaCodeReferenceElement.class, false); if (ref != null) { final PsiElement qualifier = ref.getQualifier(); if (qualifier != null) { - final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(project); + final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(qualifier.getProject()); final String parenSpace = settings.SPACE_WITHIN_PARENTHESES ? " " : ""; document.insertString(qualifier.getTextRange().getEndOffset(), parenSpace + ")"); @@ -551,7 +541,7 @@ public class JavaCompletionUtil { final int exprStart = qualifier.getTextRange().getStartOffset(); document.insertString(exprStart, prefix + spaceWithin + ")" + spaceAfter); - CompletionUtil.emulateInsertion(context, exprStart + prefix.length(), to); + CompletionUtil.emulateInsertion(context, exprStart + prefix.length(), castTypeItem); context.getEditor().getCaretModel().moveToOffset(context.getTailOffset()); } } @@ -562,24 +552,26 @@ public class JavaCompletionUtil { } public static LookupElement highlightIfNeeded(PsiType qualifierType, LookupElement item, Object object) { - if (qualifierType instanceof PsiArrayType) { - if (object instanceof PsiField || object instanceof PsiMethod) { //length and clone() - PsiElement parent = ((PsiElement)object).getParent(); - if (parent instanceof PsiClass && parent.getContainingFile().getVirtualFile() == null) { //yes, they're a bit dummy - return highlight(item); - } + return containsMember(qualifierType, object) ? highlight(item) : item; + } + + public static boolean containsMember(PsiType qualifierType, Object object) { + if (qualifierType instanceof PsiArrayType && object instanceof PsiMember) { //length and clone() + if (((PsiMember)object).getContainingFile().getVirtualFile() == null) { //yes, they're a bit dummy + return true; } } else if (qualifierType instanceof PsiClassType) { PsiClass qualifierClass = ((PsiClassType)qualifierType).resolve(); - if (object instanceof PsiField || object instanceof PsiMethod || object instanceof PsiClass) { - PsiClass parent = ((PsiMember)object).getContainingClass(); - if (parent != null && parent.equals(qualifierClass)) { - return highlight(item); - } + if (qualifierClass == null) return false; + if (object instanceof PsiMethod) { + return qualifierClass.findMethodBySignature((PsiMethod)object, false) != null; + } + if (object instanceof PsiMember) { + return qualifierClass.equals(((PsiMember)object).getContainingClass()); } } - return item; + return false; } private static LookupElement highlight(LookupElement decorator) { @@ -593,7 +585,7 @@ public class JavaCompletionUtil { }), 1); } - private static LookupItem createLookupElement(CompletionElement completionElement, PsiType qualifierType) { + private static LookupElement createLookupElement(CompletionElement completionElement) { Object completion = completionElement.getElement(); assert !(completion instanceof LookupElement); @@ -601,14 +593,12 @@ public class JavaCompletionUtil { LookupElement _ret = LookupItemUtil.objectToLookupItem(completion); if (_ret == null || !(_ret instanceof LookupItem)) return null; - LookupItem ret = (LookupItem)_ret; final PsiSubstitutor substitutor = completionElement.getSubstitutor(); if (substitutor != null) { - ret.setAttribute(LookupItem.SUBSTITUTOR, substitutor); + ((LookupItem)_ret).setAttribute(LookupItem.SUBSTITUTOR, substitutor); } - ret.putUserData(QUALIFIER_TYPE_ATTR, qualifierType); - return ret; + return _ret; } public static boolean hasAccessibleConstructor(PsiType type) { @@ -928,4 +918,21 @@ public class JavaCompletionUtil { context.setAddCompletionChar(false); return true; } + + public static FakePsiElement createContextWithXxxVariable(final PsiElement place, final PsiType varType) { + return new FakePsiElement() { + @Override + public boolean processDeclarations(@NotNull PsiScopeProcessor processor, + @NotNull ResolveState state, + PsiElement lastParent, + @NotNull PsiElement place) { + return processor.execute(new LightVariableBuilder("xxx", varType, place), ResolveState.initial()); + } + + @Override + public PsiElement getParent() { + return place; + } + }; + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java index 52da4c0f460f..5033f6a629cd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -33,11 +33,8 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.filters.*; import com.intellij.psi.filters.element.ModifierFilter; import com.intellij.psi.filters.types.AssignableFromFilter; -import com.intellij.psi.impl.FakePsiElement; -import com.intellij.psi.impl.light.LightVariableBuilder; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.infos.CandidateInfo; -import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -445,24 +442,8 @@ public class ReferenceExpressionCompletionContributor { .createExpressionFromText(((PsiClass)qualifierItem.getObject()).getQualifiedName() + ".xxx", place); } - return (PsiReferenceExpression) factory.createExpressionFromText("xxx.xxx", createContextWithXxxVariable(place, qualifierType)); - } - - public static FakePsiElement createContextWithXxxVariable(final PsiElement place, final PsiType varType) { - return new FakePsiElement() { - @Override - public boolean processDeclarations(@NotNull PsiScopeProcessor processor, - @NotNull ResolveState state, - PsiElement lastParent, - @NotNull PsiElement place) { - return processor.execute(new LightVariableBuilder("xxx", varType, place), ResolveState.initial()); - } - - @Override - public PsiElement getParent() { - return place; - } - }; + return (PsiReferenceExpression) factory.createExpressionFromText("xxx.xxx", JavaCompletionUtil + .createContextWithXxxVariable(place, qualifierType)); } private static boolean shoudChain(PsiElement element, PsiType qualifierType, PsiType expectedType, LookupElement item) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java index 95c74648027a..5723681ecde3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java @@ -85,7 +85,7 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme if (qualifier instanceof PsiSuperExpression) { final PsiJavaCodeReferenceElement qSuper = ((PsiSuperExpression)qualifier).getQualifier(); if (qSuper == null) { - myQualifierClass = JavaResolveUtil.getContextClass(myElement); + myQualifierClass = JavaResolveUtil.getContextClass( myElement); } else { final PsiElement target = qSuper.resolve(); myQualifierClass = target instanceof PsiClass ? (PsiClass)target : null; diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java index 7d04ecd1275b..b00372cc9552 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java @@ -46,6 +46,7 @@ public class PsiTypeLookupItem extends LookupItem { myBracketsCount = bracketsCount; } + @NotNull public PsiType getPsiType() { Object object = getObject(); PsiType type = object instanceof PsiType ? (PsiType)object : JavaPsiFacade.getElementFactory(((PsiClass) object).getProject()).createType((PsiClass)object); diff --git a/java/java-tests/testData/codeInsight/completion/normal/CastVisually.java b/java/java-tests/testData/codeInsight/completion/normal/CastVisually.java new file mode 100644 index 000000000000..17d30a741d08 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/CastVisually.java @@ -0,0 +1,14 @@ +import java.lang.Object; + +class IFoo { + Object getValue() {} +} + +class Foo extends IFoo { + Foo getValue() {} + void foo(IFoo o) { + if (o instanceof Foo) { + o.getvx + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 383ca96325ae..6444c21173bb 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1300,4 +1300,12 @@ public class ListUtils { checkResult() } + public void testCastVisually() { + configure() + def p = LookupElementPresentation.renderElement(myFixture.lookupElements[0]) + assert p.itemText == 'getValue' + assert p.itemTextBold + assert p.typeText == 'Foo' + } + } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java index 70ae6f0bd85f..cba75c7052a9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java @@ -125,7 +125,7 @@ public class GroovyNoVariantsDelegator extends CompletionContributor { } return factory.createReferenceExpressionFromText("xxx.xxx", - ReferenceExpressionCompletionContributor + JavaCompletionUtil .createContextWithXxxVariable(place, qualifierType)); } From 968bfa0474148487c7cdf2d8dc0fc86c79677f7b Mon Sep 17 00:00:00 2001 From: irengrig Date: Fri, 9 Mar 2012 16:01:21 +0400 Subject: [PATCH 07/44] IDEA-82430 "Changes" window - "Repository" tab, "Group by" combobox unnessesarily clip text (?) --- .../openapi/vcs/changes/committed/LabeledComboBoxAction.java | 4 ++++ .../openapi/vcs/changes/committed/SelectGroupingAction.java | 1 + 2 files changed, 5 insertions(+) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/LabeledComboBoxAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/LabeledComboBoxAction.java index 572f101e1953..540cc5985b6a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/LabeledComboBoxAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/LabeledComboBoxAction.java @@ -93,4 +93,8 @@ public abstract class LabeledComboBoxAction extends AnAction implements CustomCo boxModel.setSelectedItem(boxModel.getElementAt(idx)); } } + + protected JComboBox getComboBox() { + return myComboBox; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/SelectGroupingAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/SelectGroupingAction.java index e67325582563..0ed24cc232f5 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/SelectGroupingAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/SelectGroupingAction.java @@ -26,6 +26,7 @@ public class SelectGroupingAction extends LabeledComboBoxAction { public SelectGroupingAction(final CommittedChangesTreeBrowser browser) { super("Group by"); myBrowser = browser; + getComboBox().setPrototypeDisplayValue("Date+"); } protected void selectionChanged(Object selection) { From ace67be72dce66665f5a65e8e68e5fb6e3009356 Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Fri, 9 Mar 2012 16:00:32 +0400 Subject: [PATCH 08/44] IDEA-81546 'New...' button near SDK combo at Dependencies tab should open file chooser to select Flex SDK home --- .../roots/ui/configuration/JdkComboBox.java | 34 +++++++++++++------ .../projectRoot/ProjectSdksModel.java | 9 +++++ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java index a6d238a8688e..aae24ea21e63 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java @@ -17,10 +17,11 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.ide.DataManager; import com.intellij.ide.util.projectWizard.ProjectJdkListRenderer; -import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkType; import com.intellij.openapi.roots.ui.configuration.projectRoot.JdkListConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.ui.ComboBoxWithWidePopup; @@ -48,15 +49,20 @@ import java.util.List; public class JdkComboBox extends ComboBoxWithWidePopup { @Nullable - private Condition myFilter; - + private final Condition myFilter; + @Nullable + private final Condition myCreationFilter; + public JdkComboBox(@NotNull final ProjectSdksModel jdkModel) { - this(jdkModel, null); + this(jdkModel, null, null); } - public JdkComboBox(@NotNull final ProjectSdksModel jdkModel, @Nullable Condition filter) { + public JdkComboBox(@NotNull final ProjectSdksModel jdkModel, + @Nullable Condition filter, + @Nullable Condition creationFilter) { super(new JdkComboBoxModel(jdkModel, filter)); myFilter = filter; + myCreationFilter = creationFilter; setRenderer(new ProjectJdkListRenderer(getRenderer()) { @Override public void doCustomize(JList list, Object value, int index, boolean selected, boolean hasFocus) { @@ -137,12 +143,18 @@ public class JdkComboBox extends ComboBoxWithWidePopup { } } } - }); - JBPopupFactory.getInstance() - .createActionGroupPopup(actionGroupTitle, group, - DataManager.getInstance().getDataContext(JdkComboBox.this), JBPopupFactory.ActionSelectionAid.MNEMONICS, - false) - .showUnderneathOf(setUpButton); + }, myCreationFilter); + final DataContext dataContext = DataManager.getInstance().getDataContext(JdkComboBox.this); + if (group.getChildrenCount() > 1) { + JBPopupFactory.getInstance() + .createActionGroupPopup(actionGroupTitle, group, dataContext, JBPopupFactory.ActionSelectionAid.MNEMONICS, false) + .showUnderneathOf(setUpButton); + } + else { + final AnActionEvent event = + new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, new Presentation(""), ActionManager.getInstance(), 0); + group.getChildren(event)[0].actionPerformed(event); + } } }); } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java index eef29826d38a..bfd33af9a830 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java @@ -32,6 +32,7 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.MasterDetailsComponent; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Condition; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import com.intellij.util.EventDispatcher; @@ -214,8 +215,16 @@ public class ProjectSdksModel implements SdkModel { } public void createAddActions(DefaultActionGroup group, final JComponent parent, final Consumer updateTree) { + createAddActions(group, parent, updateTree, null); + } + + public void createAddActions(DefaultActionGroup group, + final JComponent parent, + final Consumer updateTree, + @Nullable Condition filter) { final SdkType[] types = SdkType.getAllTypes(); for (final SdkType type : types) { + if (filter != null && !filter.value(type)) continue; final AnAction addAction = new DumbAwareAction(type.getPresentableName(), null, type.getIconForAddAction()) { From 712fb2efde8af3465c5cab893dff4c596f9ef1b1 Mon Sep 17 00:00:00 2001 From: Serega Vasiliev Date: Fri, 9 Mar 2012 13:19:53 +0100 Subject: [PATCH 09/44] Hibernate 4: library type, new file templates, download --- .../download/impl/FileSetVersionsFetcherBase.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/download/impl/FileSetVersionsFetcherBase.java b/platform/lang-impl/src/com/intellij/util/download/impl/FileSetVersionsFetcherBase.java index 6ed7a278cb3b..cef0acf2dba3 100644 --- a/platform/lang-impl/src/com/intellij/util/download/impl/FileSetVersionsFetcherBase.java +++ b/platform/lang-impl/src/com/intellij/util/download/impl/FileSetVersionsFetcherBase.java @@ -70,9 +70,17 @@ public abstract class FileSetVersionsFetcherBase Date: Fri, 9 Mar 2012 16:33:45 +0400 Subject: [PATCH 10/44] fix tests --- .../codeInsight/completion/JavaCompletionUtil.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 12adae0a1fcd..60a9855b45e9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -557,15 +557,16 @@ public class JavaCompletionUtil { public static boolean containsMember(PsiType qualifierType, Object object) { if (qualifierType instanceof PsiArrayType && object instanceof PsiMember) { //length and clone() - if (((PsiMember)object).getContainingFile().getVirtualFile() == null) { //yes, they're a bit dummy + PsiFile file = ((PsiMember)object).getContainingFile(); + if (file == null || file.getVirtualFile() == null) { //yes, they're a bit dummy return true; } } else if (qualifierType instanceof PsiClassType) { PsiClass qualifierClass = ((PsiClassType)qualifierType).resolve(); if (qualifierClass == null) return false; - if (object instanceof PsiMethod) { - return qualifierClass.findMethodBySignature((PsiMethod)object, false) != null; + if (object instanceof PsiMethod && qualifierClass.findMethodBySignature((PsiMethod)object, false) != null) { + return true; } if (object instanceof PsiMember) { return qualifierClass.equals(((PsiMember)object).getContainingClass()); From 74c6839c1fbea433a09f691736d23b54635fe269 Mon Sep 17 00:00:00 2001 From: irengrig Date: Fri, 9 Mar 2012 16:44:14 +0400 Subject: [PATCH 11/44] SVN: better set property diagnostics --- .../org/jetbrains/idea/svn/dialogs/PropertiesComponent.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java index 7cfc6fa8b34a..52d98fae9386 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java @@ -18,8 +18,10 @@ package org.jetbrains.idea.svn.dialogs; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; +import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.wm.ToolWindowManager; @@ -333,6 +335,7 @@ public class PropertiesComponent extends JPanel { wcClient.doSetProperty(myFile, name, SVNPropertyValue.create(value), false, recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY, null, null); } catch (SVNException err) { + VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + err.getMessage(), MessageType.ERROR); // show error message } } From eae672a281b77906f4f665229df54836b8a050f8 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 9 Mar 2012 16:41:57 +0400 Subject: [PATCH 12/44] IDEA-66226: Pay respect to [CDATA] inside tags (InjectionValueStyleInspection # checkValue ) --- .../psi/impl/source/xml/XmlTagValueImpl.java | 14 ++++++++++++++ .../src/com/intellij/psi/xml/XmlTagValue.java | 2 ++ 2 files changed, 16 insertions(+) diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java index e03bdfdf5a8a..f68e7e48bb9f 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java +++ b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java @@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; import com.intellij.psi.XmlElementFactory; import com.intellij.psi.xml.*; import com.intellij.util.IncorrectOperationException; @@ -123,4 +124,17 @@ public class XmlTagValueImpl implements XmlTagValue{ LOG.error(e); } } + + @Override + public boolean hasCDATA() { + for (XmlText xmlText : myTextElements) { + PsiElement[] children = xmlText.getChildren(); + for (PsiElement child : children) { + if (child.getNode().getElementType() == XmlElementType.XML_CDATA) { + return true; + } + } + } + return false; + } } diff --git a/xml/openapi/src/com/intellij/psi/xml/XmlTagValue.java b/xml/openapi/src/com/intellij/psi/xml/XmlTagValue.java index 9e922e58f907..aedef5bbb975 100644 --- a/xml/openapi/src/com/intellij/psi/xml/XmlTagValue.java +++ b/xml/openapi/src/com/intellij/psi/xml/XmlTagValue.java @@ -36,4 +36,6 @@ public interface XmlTagValue { String getTrimmedText(); void setText(String value); + + boolean hasCDATA(); } From f69508e8134ae9564b5b5f69235c74389f863518 Mon Sep 17 00:00:00 2001 From: irengrig Date: Fri, 9 Mar 2012 16:54:15 +0400 Subject: [PATCH 13/44] SVN: better edit/delete property diagnostics --- .../org/jetbrains/idea/svn/dialogs/PropertiesComponent.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java index 52d98fae9386..ebb92267e41e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java @@ -281,6 +281,7 @@ public class PropertiesComponent extends JPanel { } catch (SVNException err) { // show error message + VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + err.getMessage(), MessageType.ERROR); } } setFile(myVcs, myFile); @@ -302,6 +303,7 @@ public class PropertiesComponent extends JPanel { try { myVcs.createWCClient().doSetProperty(myFile, getSelectedPropertyName(), null, true, false, null); } catch (SVNException error) { + VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + error.getMessage(), MessageType.ERROR); // show error message. } setFile(myVcs, myFile); @@ -368,6 +370,7 @@ public class PropertiesComponent extends JPanel { wcClient.doSetProperty(myFile, name, SVNPropertyValue.create(value), false, recursive, null); } catch (SVNException err) { + VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + err.getMessage(), MessageType.ERROR); // show error message } } From abc2740b81133def176a07e6817d21a72db36ec8 Mon Sep 17 00:00:00 2001 From: irengrig Date: Fri, 9 Mar 2012 18:24:21 +0400 Subject: [PATCH 14/44] IDEA-82489 Subversion: native client + externals, native client + unversioned modules --- .../SvnCommandLineStatusClient.java | 5 ++- .../svn/commandLine/SvnStatusHandler.java | 41 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java index 7c2f8bdaddf2..1f351951bb9d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java @@ -19,6 +19,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.containers.Convertor; +import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.portable.PortableStatus; import org.jetbrains.idea.svn.portable.SvnExceptionWrapper; import org.jetbrains.idea.svn.portable.SvnStatusClientI; @@ -159,7 +160,9 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); parser.parse(new StringBufferInputStream(result), svnHandl[0]); if (! svnHandl[0].isAnythingReported()) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY)); + if (! SvnUtil.isSvnVersioned(myProject, path)) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY)); + } } } catch (SvnExceptionWrapper e) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnStatusHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnStatusHandler.java index c07f4cb00a31..edda617b3b33 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnStatusHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnStatusHandler.java @@ -684,6 +684,47 @@ public class SvnStatusHandler extends DefaultHandler { if (exists) { status.setKind(exists, file.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE); } else { + // this is a hack. This is done so because of strange svn native client output: + /* + c:\TestProjects\sortedProjects\Subversion\local\withExt82420\mod4>svn st --xml + + + + + + + + + + + while + +c:\TestProjects\sortedProjects\Subversion\local\withExt82420\mod4>dir + Volume in drive C has no label. + Volume Serial Number is B4EA-B379 + + Directory of c:\TestProjects\sortedProjects\Subversion\local\withExt82420\mod4 + +03/09/2012 05:30 PM . +03/09/2012 05:30 PM .. +03/09/2012 05:30 PM 437 mod4.iml +03/09/2012 05:30 PM src + +and no "mod4" under + + */ + final SVNStatusType ns = status.getNodeStatus(); + if (myBase.getName().equals(path) && ! SVNStatusType.MISSING.equals(ns) && + ! SVNStatusType.STATUS_DELETED.equals(ns) ) { + status.setKind(true, SVNNodeKind.DIR); + status.setFile(myBase); + status.setPath(""); + return; + } status.setKind(exists, SVNNodeKind.UNKNOWN); } status.setPath(path); From 3d511ef0acb0fcb5744c32206eb12a45d513a763 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Fri, 9 Mar 2012 17:27:31 +0100 Subject: [PATCH 15/44] testDataProvider - assertion --- .../src/com/intellij/testFramework/TestDataProvider.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/platform/testFramework/src/com/intellij/testFramework/TestDataProvider.java b/platform/testFramework/src/com/intellij/testFramework/TestDataProvider.java index 75113e470776..dd6e7a0c2653 100644 --- a/platform/testFramework/src/com/intellij/testFramework/TestDataProvider.java +++ b/platform/testFramework/src/com/intellij/testFramework/TestDataProvider.java @@ -40,6 +40,11 @@ public class TestDataProvider implements DataProvider { @Override public Object getData(@NonNls String dataId) { + if (myProject.isDisposed()) { + throw new RuntimeException("TestDataProvider is already disposed.\n" + + "If you closed a project in test, please reset IdeaTestApplication.setDataProvider."); + } + if (PlatformDataKeys.PROJECT.is(dataId)) { return myProject; } From dad6b5c04c976e4f2ab94d40a619548e29a9f5a8 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 19:02:54 +0400 Subject: [PATCH 16/44] remove unneeded dependency --- java/java-psi-impl/java-psi-impl.iml | 1 - 1 file changed, 1 deletion(-) diff --git a/java/java-psi-impl/java-psi-impl.iml b/java/java-psi-impl/java-psi-impl.iml index ef7bdab73a0c..ccd2d51410f9 100644 --- a/java/java-psi-impl/java-psi-impl.iml +++ b/java/java-psi-impl/java-psi-impl.iml @@ -12,7 +12,6 @@ - From 14cd4a02fc053865f4bddbbd21cbe4eb4258a313 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 19:40:13 +0400 Subject: [PATCH 17/44] IDEA-64052 Gant target names are duplicated in Code Completion --- .../GroovyAssignabilityCheckInspection.java | 1 + .../GroovyNamedArgumentProvider.java | 31 ++++++++++++++----- .../groovy/gant/GantMemberContributor.java | 17 +++++----- .../MapArgumentCompletionProvider.java | 5 +++ .../psi/impl/GroovyResolveResultImpl.java | 8 +++++ .../gant/GantReferenceCompletionTest.groovy | 11 ++----- .../groovy/lang/GroovyMapAttributeTest.groovy | 7 ++++- 7 files changed, 56 insertions(+), 24 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java index dab16040291e..e62afa172b81 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java @@ -475,6 +475,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { if (namedArguments.length == 0) return; Map map = GroovyNamedArgumentProvider.getNamedArgumentsFromAllProviders(call, null, false); + if (map == null) return; for (GrNamedArgument namedArgument : namedArguments) { String labelName = namedArgument.getLabelName(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java index 5c09dc23b945..f6cc56bccc94 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java @@ -16,17 +16,17 @@ package org.jetbrains.plugins.groovy.extensions; import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.psi.CommonClassNames; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiParameter; +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import java.util.HashMap; import java.util.Map; @@ -56,6 +56,7 @@ public abstract class GroovyNamedArgumentProvider { getNamedArguments(call, resolve, argumentName, forCompletion, result); } + @Nullable public static Map getNamedArgumentsFromAllProviders(@NotNull GrCall call, @Nullable String argumentName, boolean forCompletion) { @@ -80,6 +81,7 @@ public abstract class GroovyNamedArgumentProvider { } } else { + boolean mapExpected = false; for (GroovyResolveResult result : callVariants) { PsiElement element = result.getElement(); if (element instanceof GrAccessorMethod) continue; @@ -90,6 +92,8 @@ public abstract class GroovyNamedArgumentProvider { if (!method.isConstructor() && !(parameters.length > 0 && canBeMap(parameters[0]))) continue; + mapExpected = true; + for (GroovyMethodInfo methodInfo : GroovyMethodInfo.getInfos(method)) { if (methodInfo.getNamedArguments() != null) { if (methodInfo.isApplicable(method)) { @@ -107,16 +111,27 @@ public abstract class GroovyNamedArgumentProvider { for (GroovyNamedArgumentProvider namedArgumentProvider : EP_NAME.getExtensions()) { namedArgumentProvider.getNamedArguments(call, element, result, argumentName, forCompletion, namedArguments); } + + if (element instanceof GrVariable && + InheritanceUtil.isInheritor(((GrVariable)element).getTypeGroovy(), GroovyCommonClassNames.GROOVY_LANG_CLOSURE)) { + mapExpected = true; + } + } + if (!mapExpected && namedArguments.isEmpty()) { + return null; } } return namedArguments; } - public static boolean canBeMap(PsiParameter parameter) { - if (parameter instanceof GrParameter) { - if (((GrParameter)parameter).getTypeElementGroovy() == null) return true; + private static boolean canBeMap(PsiParameter parameter) { + PsiType type = parameter.getType(); + if (parameter instanceof GrParameter && + type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) && + ((GrParameter)parameter).getTypeElementGroovy() == null) { + return true; } - return GroovyPsiManager.isInheritorCached(parameter.getType(), CommonClassNames.JAVA_UTIL_MAP); + return GroovyPsiManager.isInheritorCached(type, CommonClassNames.JAVA_UTIL_MAP); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java index 5be4f0e7ed4e..0b3ab60c8134 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java @@ -29,6 +29,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlo import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -84,13 +85,15 @@ public class GantMemberContributor extends NonCodeMembersContributor { return; } - for (GrArgumentLabel label : GantUtils.getScriptTargets((GroovyFile)file)) { - final String targetName = label.getName(); - if (targetName != null) { - final PsiNamedElement variable = new LightVariableBuilder(targetName, GroovyCommonClassNames.GROOVY_LANG_CLOSURE, label). - setBaseIcon(GantIcons.GANT_TARGET); - if (!ResolveUtil.processElement(processor, variable, state)) { - return; + if (aClass instanceof GroovyScriptClass) { + for (GrArgumentLabel label : GantUtils.getScriptTargets((GroovyFile)file)) { + final String targetName = label.getName(); + if (targetName != null) { + final PsiNamedElement variable = new LightVariableBuilder(targetName, GroovyCommonClassNames.GROOVY_LANG_CLOSURE, label). + setBaseIcon(GantIcons.GANT_TARGET); + if (!ResolveUtil.processElement(processor, variable, state)) { + return; + } } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java index e69a65085b31..db7f4e7a8065 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java @@ -80,6 +80,10 @@ class MapArgumentCompletionProvider extends CompletionProvider map = calcNamedArgumentsForCall(mapOrArgumentList); + if (map == null) { + return; + } + if (map.isEmpty()) { map = findOtherNamedArgumentsInFile(mapOrArgumentList); } @@ -155,6 +159,7 @@ class MapArgumentCompletionProvider extends CompletionProvider calcNamedArgumentsForCall(@NotNull PsiElement mapOrArgumentList) { PsiElement argumentList = mapOrArgumentList instanceof GrArgumentList ? mapOrArgumentList : mapOrArgumentList.getParent(); if (argumentList instanceof GrArgumentList) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java index 9210e96b8ba9..e8b06b9c8eee 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java @@ -115,4 +115,12 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { public boolean isInvokedOnProperty() { return myIsInvokedOnProperty; } + + @Override + public String toString() { + return "GroovyResolveResultImpl{" + + "myElement=" + myElement + + ", mySubstitutor=" + mySubstitutor + + '}'; + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy index 35500fafe438..8ff9b61f7e00 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy @@ -83,16 +83,11 @@ target(aaa: "") { } public void testMutual() throws Throwable { - complete """ + checkVariants """ target(genga: "") { } target(aaa: "") { - depends(geng) -}""" - myFixture.checkResult """ -target(genga: "") { } -target(aaa: "") { - depends(genga) -}""" + depends(gengx) +}""", 'genga' } public void testUnknownQualifier() throws Throwable { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy index 1a328b3b87bf..a828d6e60c09 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy @@ -15,16 +15,21 @@ */ package org.jetbrains.plugins.groovy.lang -import com.intellij.codeInsight.completion.CompletionType import com.intellij.codeInsight.lookup.LookupElement import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyUncheckedAssignmentOfMemberOfRawTypeInspection +import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.plugins.groovy.completion.GrCompletionWithLibraryTest /** * @author Sergey Evdokimov */ class GroovyMapAttributeTest extends LightCodeInsightFixtureTestCase { + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return GrCompletionWithLibraryTest.GROOVY_17_PROJECT_DESCRIPTOR + } private void doTestCompletion(String fileText, boolean exists) { myFixture.configureByText("a.groovy", fileText) From d796ecea555e1c247c5d66617816b179f1a6fc46 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 20:36:04 +0400 Subject: [PATCH 18/44] normal methods should have higher priority than Collections.emptyList --- ...referLocalVariablesLiteralsAndAnnoMethodsWeigher.java | 9 +++++++-- .../com/intellij/psi/filters/getters/MembersGetter.java | 9 ++++++--- .../smartTypeSorting/PreferCollectionsEmptyList.java | 8 ++++++-- .../completion/SmartTypeCompletionOrderingTest.groovy | 6 +++--- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java index 5899de6213c5..7c1a3b877601 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementWeigher; import com.intellij.psi.*; +import com.intellij.psi.filters.getters.MembersGetter; import com.intellij.psi.util.PropertyUtil; import org.jetbrains.annotations.NotNull; @@ -44,8 +45,9 @@ public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends LookupEle qualifiedWithField, qualifiedWithGetter, superMethodParameters, - collectionFactory, normal, + collectionFactory, + expectedTypeMember, nonInitialized, classLiteral, className, @@ -75,7 +77,10 @@ public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends LookupEle if (item.getUserData(CollectionsUtilityMethodsProvider.COLLECTION_FACTORY) != null) { return MyResult.collectionFactory; } - + if (Boolean.TRUE.equals(item.getUserData(MembersGetter.EXPECTED_TYPE_INHERITOR_MEMBER))) { + return MyResult.expectedTypeMember; + } + final JavaChainLookupElement chain = item.as(JavaChainLookupElement.CLASS_CONDITION_KEY); if (chain != null) { Object qualifier = chain.getQualifier().getObject(); diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java b/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java index a6af89daad40..8923ff7ba34a 100644 --- a/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java +++ b/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java @@ -22,6 +22,7 @@ import com.intellij.codeInsight.completion.StaticMemberProcessor; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Key; import com.intellij.psi.*; import com.intellij.psi.filters.TrueFilter; import com.intellij.psi.scope.processor.FilterScopeProcessor; @@ -43,6 +44,7 @@ import java.util.Set; * @author peter */ public abstract class MembersGetter { + public static final Key EXPECTED_TYPE_INHERITOR_MEMBER = Key.create("EXPECTED_TYPE_INHERITOR_MEMBER"); public void processMembers(@NotNull final PsiElement context, final Consumer results, @Nullable final PsiClass where, final boolean acceptMethods, boolean searchInheritors, @@ -85,7 +87,7 @@ public abstract class MembersGetter { final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper(); - PsiClassType baseType = JavaPsiFacade.getElementFactory(where.getProject()).createType(where); + final PsiClassType baseType = JavaPsiFacade.getElementFactory(where.getProject()).createType(where); Consumer consumer = new Consumer() { @Override public void consume(PsiType psiType) { @@ -97,7 +99,7 @@ public abstract class MembersGetter { return; } } - processClassDeclaredMembers(psiClass, context, acceptMethods, results, resolveHelper, importedStatically); + processClassDeclaredMembers(psiClass, context, acceptMethods, results, resolveHelper, importedStatically, psiType != baseType); } } }; @@ -110,7 +112,7 @@ public abstract class MembersGetter { private void processClassDeclaredMembers(PsiClass where, PsiElement context, boolean acceptMethods, - Consumer results, final PsiResolveHelper resolveHelper, final Set importedStatically) { + Consumer results, final PsiResolveHelper resolveHelper, final Set importedStatically, boolean isInheritor) { final FilterScopeProcessor processor = new FilterScopeProcessor(TrueFilter.INSTANCE); where.processDeclarations(processor, ResolveState.initial(), null, context); @@ -123,6 +125,7 @@ public abstract class MembersGetter { if (result instanceof PsiMethod && acceptMethods) continue; final LookupElement item = result instanceof PsiMethod ? createMethodElement((PsiMethod)result) : createFieldElement((PsiField)result); if (item != null) { + item.putUserData(EXPECTED_TYPE_INHERITOR_MEMBER, isInheritor); results.consume(AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(item)); } } diff --git a/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferCollectionsEmptyList.java b/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferCollectionsEmptyList.java index 2770782a68bc..0b6920c6ed53 100644 --- a/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferCollectionsEmptyList.java +++ b/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferCollectionsEmptyList.java @@ -1,8 +1,12 @@ +import java.util.List; + public class Aaaaaaa { + List locMethod() {} + { - java.util.List local = null; - java.util.List l = + List local = null; + List l = } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy index 2480cc6bca78..0c853406a0ab 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy @@ -291,9 +291,9 @@ public class SmartTypeCompletionOrderingTest extends CompletionSortingTestCase { myFixture.addClass("package foo; public class FList implements java.util.List { public static FList emptyList() {} }"); configureNoCompletion(getTestName(false) + ".java"); myFixture.complete(CompletionType.SMART, 2); - assertPreferredItems(0, "local", "local.subList", "emptyList", "singletonList", "unmodifiableList"); - assert 'Collections.emptyList' in lookup.items[2].allLookupStrings - assert 'FList.emptyList' in lookup.items[5].allLookupStrings + assertPreferredItems(0, "local", "local.subList", "locMethod", "locMethod().subList", "emptyList", "singletonList", "unmodifiableList", "emptyList"); + assert 'Collections.emptyList' in lookup.items[4].allLookupStrings + assert 'FList.emptyList' in lookup.items[7].allLookupStrings } public void testDispreferGetterInSetterCall() { From 9a93bae85e6058a92a42f3b7cb10bb7e64b285fd Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 20:52:59 +0400 Subject: [PATCH 19/44] DRY --- .../BasicExpressionCompletionContributor.java | 6 +- .../CollectionsUtilityMethodsProvider.java | 71 ++++++++++--------- 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java index cedc14ed900a..ec44f00d15bb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.lookup.*; import com.intellij.codeInsight.template.SmartCompletionContextType; import com.intellij.codeInsight.template.impl.TemplateImpl; import com.intellij.codeInsight.template.impl.TemplateSettings; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.psi.filters.getters.ClassLiteralGetter; @@ -67,7 +68,10 @@ public class BasicExpressionCompletionContributor { } if (!AFTER_DOT.accepts(element)) { - CollectionsUtilityMethodsProvider.addCompletions(parameters, result); + new CollectionsUtilityMethodsProvider(parameters.getPosition(), + parameters.getExpectedType(), + parameters.getDefaultType(), result) + .addCompletions(parameters.getParameters().getInvocationCount() > 1 || StringUtil.isNotEmpty(matcher.getPrefix())); ClassLiteralGetter.addCompletions(parameters, result, matcher); final PsiElement position = parameters.getPosition(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java index 5f59dcf6d378..9411f764f8df 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java @@ -30,55 +30,62 @@ import static com.intellij.psi.CommonClassNames.*; */ class CollectionsUtilityMethodsProvider { public static final Key COLLECTION_FACTORY = Key.create("CollectionFactory"); - - public static void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, - @NotNull final Consumer result) { - final PsiElement element = parameters.getPosition(); + private final PsiElement myElement; + private final PsiType myExpectedType; + private final PsiType myDefaultType; + @NotNull private final Consumer myResult; - final PsiElement parent = element.getParent(); + CollectionsUtilityMethodsProvider(PsiElement position, + PsiType expectedType, + PsiType defaultType, @NotNull final Consumer result) { + myResult = result; + myElement = position; + myExpectedType = expectedType; + myDefaultType = defaultType; + } + + public void addCompletions(boolean showAll) { + final PsiElement parent = myElement.getParent(); if (parent instanceof PsiReferenceExpression && ((PsiReferenceExpression)parent).getQualifierExpression() != null) return; final PsiClass collectionsClass = - JavaPsiFacade.getInstance(element.getProject()).findClass(JAVA_UTIL_COLLECTIONS, element.getResolveScope()); + JavaPsiFacade.getInstance(myElement.getProject()).findClass(JAVA_UTIL_COLLECTIONS, myElement.getResolveScope()); if (collectionsClass == null) return; - final PsiType type = parameters.getExpectedType(); - final PsiType defaultType = parameters.getDefaultType(); final PsiElement pparent = parent.getParent(); - if (parameters.getParameters().getInvocationCount() > 1 || + if (showAll || pparent instanceof PsiReturnStatement || pparent instanceof PsiConditionalExpression && pparent.getParent() instanceof PsiReturnStatement) { - addCollectionMethod(result, type, defaultType, JAVA_UTIL_LIST, "emptyList", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_SET, "emptySet", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_MAP, "emptyMap", collectionsClass, element); + addCollectionMethod(JAVA_UTIL_LIST, "emptyList", collectionsClass); + addCollectionMethod(JAVA_UTIL_SET, "emptySet", collectionsClass); + addCollectionMethod(JAVA_UTIL_MAP, "emptyMap", collectionsClass); } - if (parameters.getParameters().getInvocationCount() > 1) { - addCollectionMethod(result, type, defaultType, JAVA_UTIL_LIST, "singletonList", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_SET, "singleton", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_MAP, "singletonMap", collectionsClass, element); + if (showAll) { + addCollectionMethod(JAVA_UTIL_LIST, "singletonList", collectionsClass); + addCollectionMethod(JAVA_UTIL_SET, "singleton", collectionsClass); + addCollectionMethod(JAVA_UTIL_MAP, "singletonMap", collectionsClass); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_COLLECTION, "unmodifiableCollection", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_LIST, "unmodifiableList", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_SET, "unmodifiableSet", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_MAP, "unmodifiableMap", collectionsClass, element); - addCollectionMethod(result, type, defaultType, "java.util.SortedSet", "unmodifiableSortedSet", collectionsClass, element); - addCollectionMethod(result, type, defaultType, "java.util.SortedMap", "unmodifiableSortedMap", collectionsClass, element); + addCollectionMethod(JAVA_UTIL_COLLECTION, "unmodifiableCollection", collectionsClass); + addCollectionMethod(JAVA_UTIL_LIST, "unmodifiableList", collectionsClass); + addCollectionMethod(JAVA_UTIL_SET, "unmodifiableSet", collectionsClass); + addCollectionMethod(JAVA_UTIL_MAP, "unmodifiableMap", collectionsClass); + addCollectionMethod("java.util.SortedSet", "unmodifiableSortedSet", collectionsClass); + addCollectionMethod("java.util.SortedMap", "unmodifiableSortedMap", collectionsClass); } } - private static void addCollectionMethod(final Consumer result, final PsiType expectedType, - final PsiType defaultType, final String baseClassName, - @NonNls final String method, @NotNull final PsiClass collectionsClass, PsiElement place) { - if (isClassType(expectedType, baseClassName) || isClassType(expectedType, JAVA_UTIL_COLLECTION)) { - addMethodItem(result, expectedType, method, collectionsClass, place); - } else if (isClassType(defaultType, baseClassName) || isClassType(defaultType, JAVA_UTIL_COLLECTION)) { - addMethodItem(result, defaultType, method, collectionsClass, place); + private void addCollectionMethod(final String baseClassName, + @NonNls final String method, @NotNull final PsiClass collectionsClass) { + if (isClassType(myExpectedType, baseClassName) || isClassType(myExpectedType, JAVA_UTIL_COLLECTION)) { + addMethodItem(myExpectedType, method, collectionsClass); + } else if (isClassType(myDefaultType, baseClassName) || isClassType(myDefaultType, JAVA_UTIL_COLLECTION)) { + addMethodItem(myDefaultType, method, collectionsClass); } } - private static void addMethodItem(Consumer result, PsiType expectedType, String methodName, PsiClass containingClass, PsiElement place) { + private void addMethodItem(PsiType expectedType, String methodName, PsiClass containingClass) { final PsiMethod[] methods = containingClass.findMethodsByName(methodName, false); if (methods.length == 0) { return; @@ -87,9 +94,9 @@ class CollectionsUtilityMethodsProvider { final PsiMethod method = methods[0]; final JavaMethodCallElement item = new JavaMethodCallElement(method, false, false); item.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); - item.setInferenceSubstitutor(SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor(method, expectedType), place); + item.setInferenceSubstitutor(SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor(method, expectedType), myElement); item.putUserData(COLLECTION_FACTORY, true); - result.consume(item); + myResult.consume(item); } private static boolean isClassType(final PsiType type, final String className) { From 37e67048122a74ae02b3291ec1d9c6257afd36f6 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 21:05:12 +0400 Subject: [PATCH 20/44] suggest collection utility methods in basic completion on non-empty prefix --- .../completion/JavaNoVariantsDelegator.java | 19 ++++++++++++++++++- .../completion/normal/SuggestEmptySet.java | 7 +++++++ .../normal/SuggestEmptySet_after.java | 8 ++++++++ .../completion/NormalCompletionTest.groovy | 7 +++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet_after.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java index 9761c51aca08..1cb0667bd7e8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java @@ -15,9 +15,11 @@ */ package com.intellij.codeInsight.completion; +import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.search.PsiShortNamesCache; @@ -55,9 +57,11 @@ public class JavaNoVariantsDelegator extends CompletionContributor { return true; } - private static void delegate(CompletionParameters parameters, CompletionResultSet result) { + private static void delegate(CompletionParameters parameters, final CompletionResultSet result) { if (parameters.getCompletionType() == CompletionType.BASIC) { PsiElement position = parameters.getPosition(); + suggestCollectionUtilities(parameters, result, position); + if (parameters.getInvocationCount() <= 1 && JavaCompletionContributor.mayStartClassName(result, false) && JavaCompletionContributor.isClassNamePossible(position)) { @@ -73,6 +77,19 @@ public class JavaNoVariantsDelegator extends CompletionContributor { } } + private static void suggestCollectionUtilities(CompletionParameters parameters, final CompletionResultSet result, PsiElement position) { + if (StringUtil.isNotEmpty(result.getPrefixMatcher().getPrefix())) { + for (ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { + new CollectionsUtilityMethodsProvider(position, info.getType(), info.getDefaultType(), new Consumer() { + @Override + public void consume(LookupElement element) { + result.addElement(element); + } + }).addCompletions(true); + } + } + } + private static void suggestChainedCalls(CompletionParameters parameters, CompletionResultSet result, PsiElement position) { PsiElement parent = position.getParent(); if (!(parent instanceof PsiJavaCodeReferenceElement)) { diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet.java new file mode 100644 index 000000000000..f70f2eaa011d --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet.java @@ -0,0 +1,7 @@ +import java.util.Set; + +class Foo { + { + Set s = em + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet_after.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet_after.java new file mode 100644 index 000000000000..a9f9ca9f5fa4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet_after.java @@ -0,0 +1,8 @@ +import java.util.Collections; +import java.util.Set; + +class Foo { + { + Set s = Collections.emptySet() + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 6444c21173bb..3de5d0e61add 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1308,4 +1308,11 @@ public class ListUtils { assert p.typeText == 'Foo' } + public void testSuggestEmptySet() { + configure() + assert 'emptySet' == myFixture.lookupElementStrings[0] + type '\n' + checkResult() + } + } From 979636e035b02e9f466bfa5fd4ddd246d70fbf62 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 21:27:52 +0400 Subject: [PATCH 21/44] extract TypeArgumentCompletionProvider --- .../completion/JavaCompletionSorting.java | 2 +- .../JavaSmartCompletionContributor.java | 94 +----------- .../TypeArgumentCompletionProvider.java | 138 ++++++++++++++++++ 3 files changed, 140 insertions(+), 94 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java index 15ec279dcd43..b8d00967cad7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -246,7 +246,7 @@ public class JavaCompletionSorting { myExpectedTypes = expectedTypes; myParameters = parameters; - final Pair pair = JavaSmartCompletionContributor.getTypeParameterInfo(parameters.getPosition()); + final Pair pair = TypeArgumentCompletionProvider.getTypeParameterInfo(parameters.getPosition()); myTypeParameter = pair == null ? null : pair.first.getTypeParameters()[pair.second.intValue()]; myLocation = new CompletionLocation(myParameters); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index ad08187d2b45..d2432ea49eb4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -18,7 +18,6 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.*; import com.intellij.codeInsight.lookup.*; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; @@ -34,10 +33,8 @@ import com.intellij.psi.impl.source.PsiLabelReference; import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.javadoc.PsiDocTag; -import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.Consumer; import com.intellij.util.ProcessingContext; import com.intellij.util.ReflectionCache; @@ -286,63 +283,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } }); - extend(CompletionType.SMART, psiElement().inside(psiElement(PsiReferenceParameterList.class)), - new CompletionProvider() { - - protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) { - final PsiElement context = parameters.getPosition(); - - final Pair pair = getTypeParameterInfo(context); - if (pair == null) return; - - final PsiClass referencedClass = pair.first; - final int parameterIndex = pair.second.intValue(); - final PsiTypeParameter[] typeParameters = referencedClass.getTypeParameters(); - final PsiTypeParameter targetParameter = typeParameters[parameterIndex]; - - boolean isLast = parameterIndex == typeParameters.length - 1; - final TailType tail = isLast ? new CharTailType('>') : TailType.COMMA; - - PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper(); - final PsiType[] psiTypes = ExpectedTypesGetter.getExpectedTypes(context, false); - if (psiTypes.length > 0) { - for (PsiType type : psiTypes) { - if (!(type instanceof PsiClassType)) continue; - final PsiClassType.ClassResolveResult result = ((PsiClassType)type).resolveGenerics(); - final PsiClass typeClass = result.getElement(); - final PsiSubstitutor substitutor = result.getSubstitutor(); - - if (!InheritanceUtil.isInheritorOrSelf(referencedClass, typeClass, true)) continue; - - final PsiSubstitutor currentSubstitutor = - TypeConversionUtil.getClassSubstitutor(typeClass, referencedClass, PsiSubstitutor.EMPTY); - for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(typeClass)) { - final PsiType argSubstitution = substitutor.substitute(parameter); - final PsiType paramSubstitution = currentSubstitutor.substitute(parameter); - final PsiType substitution = resolveHelper - .getSubstitutionForTypeParameter(targetParameter, paramSubstitution, argSubstitution, false, - PsiUtil.getLanguageLevel(context)); - if (substitution != null && substitution != PsiType.NULL) { - final LookupItem item = PsiTypeLookupItem.createLookupItem(substitution, context); - resultSet.addElement(TailTypeDecorator.withTail(item.setInsertHandler(new DefaultInsertHandler()), tail)); - } - } - } - } else { - final List typeList = Collections.singletonList((PsiClassType)TypeConversionUtil.typeParameterErasure(targetParameter)); - JavaInheritorsGetter - .processInheritors(parameters, typeList, resultSet.getPrefixMatcher(), new Consumer() { - public void consume(final PsiType type) { - final PsiClass psiClass = PsiUtil.resolveClassInType(type); - if (psiClass == null) return; - - resultSet.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(psiClass), tail)); - } - }); - - } - } - }); + extend(CompletionType.SMART, psiElement().inside(psiElement(PsiReferenceParameterList.class)), new TypeArgumentCompletionProvider()); extend(CompletionType.SMART, AFTER_NEW, new JavaInheritorsGetter(ConstructorInsertHandler.SMART_INSTANCE)); @@ -409,39 +350,6 @@ public class JavaSmartCompletionContributor extends CompletionContributor { return new JavaPsiClassReferenceElement(psiClass); } - @Nullable - public static Pair getTypeParameterInfo(PsiElement context) { - final PsiReferenceParameterList parameterList = PsiTreeUtil.getContextOfType(context, PsiReferenceParameterList.class, true); - if (parameterList == null) return null; - - PsiElement parent = parameterList.getParent(); - if (!(parent instanceof PsiJavaCodeReferenceElement)) return null; - - final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)parent; - final int parameterIndex; - - int index = 0; - final PsiTypeElement typeElement = PsiTreeUtil.getContextOfType(context, PsiTypeElement.class, true); - if(typeElement != null){ - final PsiTypeElement[] elements = referenceElement.getParameterList().getTypeParameterElements(); - while (index < elements.length) { - final PsiTypeElement element = elements[index++]; - if(element == typeElement) break; - } - } - parameterIndex = index - 1; - - if(parameterIndex < 0) return null; - final PsiElement target = referenceElement.resolve(); - if(!(target instanceof PsiClass)) return null; - - final PsiClass referencedClass = (PsiClass)target; - final PsiTypeParameter[] typeParameters = referencedClass.getTypeParameters(); - if(typeParameters.length <= parameterIndex) return null; - - return Pair.create(referencedClass, parameterIndex); - } - @NotNull public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java new file mode 100644 index 000000000000..31d7b410b4ca --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java @@ -0,0 +1,138 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.CharTailType; +import com.intellij.codeInsight.TailType; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; +import com.intellij.codeInsight.lookup.TailTypeDecorator; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.*; +import com.intellij.psi.filters.getters.ExpectedTypesGetter; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.Consumer; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; + +/** +* @author peter +*/ +class TypeArgumentCompletionProvider extends CompletionProvider { + + protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) { + final PsiElement context = parameters.getPosition(); + + final Pair pair = getTypeParameterInfo(context); + if (pair == null) return; + + final PsiType[] psiTypes = ExpectedTypesGetter.getExpectedTypes(context, false); + if (psiTypes.length > 0) { + for (PsiType type : psiTypes) { + if (type instanceof PsiClassType) { + fillExpectedTypeArgs(resultSet, context, pair.first, pair.second, ((PsiClassType)type).resolveGenerics()); + } + } + } else { + addInheritors(parameters, resultSet, pair.first, pair.second); + } + } + + private static void fillExpectedTypeArgs(CompletionResultSet resultSet, + PsiElement context, + PsiClass actualClass, + int index, + PsiClassType.ClassResolveResult expectedType) { + final PsiClass expectedClass = expectedType.getElement(); + + if (!InheritanceUtil.isInheritorOrSelf(actualClass, expectedClass, true)) return; + assert expectedClass != null; + + final PsiSubstitutor currentSubstitutor = TypeConversionUtil.getClassSubstitutor(expectedClass, actualClass, PsiSubstitutor.EMPTY); + assert currentSubstitutor != null; + + PsiTypeParameter[] params = actualClass.getTypeParameters(); + for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(expectedClass)) { + final PsiType argSubstitution = expectedType.getSubstitutor().substitute(parameter); + final PsiType paramSubstitution = currentSubstitutor.substitute(parameter); + final PsiType substitution = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper() + .getSubstitutionForTypeParameter(params[index], paramSubstitution, argSubstitution, false, PsiUtil.getLanguageLevel(context)); + if (substitution != null && substitution != PsiType.NULL) { + resultSet.addElement(TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(substitution, context), getTail(actualClass, index))); + } + } + } + + private static void addInheritors(CompletionParameters parameters, + final CompletionResultSet resultSet, + final PsiClass referencedClass, + final int parameterIndex) { + final List typeList = Collections.singletonList((PsiClassType)TypeConversionUtil.typeParameterErasure( + referencedClass.getTypeParameters()[parameterIndex])); + JavaInheritorsGetter.processInheritors(parameters, typeList, resultSet.getPrefixMatcher(), new Consumer() { + public void consume(final PsiType type) { + final PsiClass psiClass = PsiUtil.resolveClassInType(type); + if (psiClass == null) return; + + resultSet.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(psiClass), + getTail(referencedClass, parameterIndex))); + } + }); + } + + private static TailType getTail(PsiClass referencedClass, int parameterIndex) { + return parameterIndex == referencedClass.getTypeParameters().length - 1 ? new CharTailType('>') : TailType.COMMA; + } + + @Nullable + static Pair getTypeParameterInfo(PsiElement context) { + final PsiReferenceParameterList parameterList = PsiTreeUtil.getContextOfType(context, PsiReferenceParameterList.class, true); + if (parameterList == null) return null; + + PsiElement parent = parameterList.getParent(); + if (!(parent instanceof PsiJavaCodeReferenceElement)) return null; + + final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)parent; + final int parameterIndex; + + int index = 0; + final PsiTypeElement typeElement = PsiTreeUtil.getContextOfType(context, PsiTypeElement.class, true); + if(typeElement != null){ + final PsiTypeElement[] elements = referenceElement.getParameterList().getTypeParameterElements(); + while (index < elements.length) { + final PsiTypeElement element = elements[index++]; + if(element == typeElement) break; + } + } + parameterIndex = index - 1; + + if(parameterIndex < 0) return null; + final PsiElement target = referenceElement.resolve(); + if(!(target instanceof PsiClass)) return null; + + final PsiClass referencedClass = (PsiClass)target; + final PsiTypeParameter[] typeParameters = referencedClass.getTypeParameters(); + if(typeParameters.length <= parameterIndex) return null; + + return Pair.create(referencedClass, parameterIndex); + } +} From 404d2487f1e243dc6bcb994effceb26d92416f20 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 22:30:24 +0400 Subject: [PATCH 22/44] suggest to fill all the required type arguments at once (IDEA-26763) --- .../TypeArgumentCompletionProvider.java | 65 ++++++++++++++++--- .../smartType/SeveralTypeArguments-out.java | 5 ++ .../smartType/SeveralTypeArguments.java | 5 ++ .../SeveralTypeArgumentsSomeUnknown-out.java | 3 + .../SeveralTypeArgumentsSomeUnknown.java | 3 + .../smartType/afterNew/after13.java | 2 +- .../completion/SmartTypeCompletionTest.java | 6 +- 7 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown-out.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java index 31d7b410b4ca..0a1990795a09 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java @@ -17,9 +17,9 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.CharTailType; import com.intellij.codeInsight.TailType; -import com.intellij.codeInsight.lookup.PsiTypeLookupItem; -import com.intellij.codeInsight.lookup.TailTypeDecorator; +import com.intellij.codeInsight.lookup.*; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.filters.getters.ExpectedTypesGetter; import com.intellij.psi.util.InheritanceUtil; @@ -27,10 +27,12 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.Consumer; +import com.intellij.util.Function; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -59,8 +61,8 @@ class TypeArgumentCompletionProvider extends CompletionProvider typeItems = new ArrayList(); + for (int i = index; i < params.length; i++) { + PsiType arg = getExpectedTypeArg(context, i, expectedType, currentSubstitutor, params); + if (arg == null) { + arg = getExpectedTypeArg(context, index, expectedType, currentSubstitutor, params); + if (arg != null) { + resultSet.addElement(TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(arg, context), getTail(index == params.length - 1))); + } + return; + } + typeItems.add(PsiTypeLookupItem.createLookupItem(arg, context)); + } + + resultSet.addElement(LookupElementBuilder.create(typeItems.get(0).getObject(), typeItems.get(0).getLookupString()).setRenderer(new LookupElementRenderer() { + @Override + public void renderElement(LookupElement element, LookupElementPresentation presentation) { + typeItems.get(0).renderElement(presentation); + presentation.setItemText(StringUtil.join(typeItems, new Function() { + @Override + public String fun(PsiTypeLookupItem item) { + return item.getLookupString(); + } + }, ", ")); + presentation.setTailText(null); + presentation.setTypeText(null); + } + }).setInsertHandler(new InsertHandler() { + @Override + public void handleInsert(InsertionContext context, LookupElement item) { + context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset()); + for (int i = 0; i < typeItems.size(); i++) { + CompletionUtil.emulateInsertion(context, context.getTailOffset(), typeItems.get(i)); + getTail(i == typeItems.size() - 1).processTail(context.getEditor(), context.getTailOffset()); + } + context.setAddCompletionChar(false); + } + })); + } + + @Nullable + private static PsiType getExpectedTypeArg(PsiElement context, + int index, + PsiClassType.ClassResolveResult expectedType, + PsiSubstitutor currentSubstitutor, PsiTypeParameter[] params) { + PsiClass expectedClass = expectedType.getElement(); + assert expectedClass != null; for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(expectedClass)) { final PsiType argSubstitution = expectedType.getSubstitutor().substitute(parameter); final PsiType paramSubstitution = currentSubstitutor.substitute(parameter); final PsiType substitution = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper() .getSubstitutionForTypeParameter(params[index], paramSubstitution, argSubstitution, false, PsiUtil.getLanguageLevel(context)); if (substitution != null && substitution != PsiType.NULL) { - resultSet.addElement(TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(substitution, context), getTail(actualClass, index))); + return substitution; } } + return null; } private static void addInheritors(CompletionParameters parameters, @@ -94,13 +143,13 @@ class TypeArgumentCompletionProvider extends CompletionProvider') : TailType.COMMA; + private static TailType getTail(boolean last) { + return last ? new CharTailType('>') : TailType.COMMA; } @Nullable diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java new file mode 100644 index 000000000000..2c3c66313e77 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java @@ -0,0 +1,5 @@ +class HashMap {} + +public class A { + private HashMap m = new HashMap(); +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java new file mode 100644 index 000000000000..5e62309ae3d4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java @@ -0,0 +1,5 @@ +class HashMap {} + +public class A { + private HashMap m = new HashMap<>(); +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown-out.java b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown-out.java new file mode 100644 index 000000000000..0a148ef74763 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown-out.java @@ -0,0 +1,3 @@ +class AAAAA{ + AAAAA asd = new AAAAA +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown.java b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown.java new file mode 100644 index 000000000000..915b39d94441 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown.java @@ -0,0 +1,3 @@ +class AAAAA{ + AAAAA asd = new AAAAA< +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java b/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java index 4ffffb2667f1..aa55d681d903 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java @@ -1,3 +1,3 @@ class AAAAA{ - AAAAA asd = new AAAAA + AAAAA asd = new AAAAA } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index 323952086592..408c85d3bbe3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -909,9 +909,9 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { doTest(); } - public void testExcessiveTail() throws Exception { - doTest(); - } + public void testExcessiveTail() throws Exception { doTest(); } + public void testSeveralTypeArguments() throws Exception { doTest(); } + public void testSeveralTypeArgumentsSomeUnknown() throws Exception { doTest(); } public void testExtendsInTypeCast() throws Exception { doTest(); From ed3f7f1132825f2ba484fb06e17ea43cd7af5594 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 23:05:53 +0400 Subject: [PATCH 23/44] position caret to the next probable editing location after inserting type arguments (IDEA-26763) --- .../completion/ConstructorInsertHandler.java | 16 ++- .../JavaSmartCompletionContributor.java | 7 +- .../TypeArgumentCompletionProvider.java | 121 +++++++++++++----- .../smartType/SeveralTypeArguments-out.java | 4 +- .../smartType/SeveralTypeArguments.java | 2 +- .../smartType/afterNew/after12.java | 2 +- .../smartType/afterNew/after13.java | 2 +- 7 files changed, 112 insertions(+), 42 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java index 80df0986a2f3..b68572f1c4af 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java @@ -26,6 +26,7 @@ import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; @@ -147,8 +148,16 @@ class ConstructorInsertHandler implements InsertHandler completeReference(final PsiElement element, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java index 0a1990795a09..f074a9b140c4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java @@ -16,12 +16,16 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.CharTailType; +import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.TailType; -import com.intellij.codeInsight.lookup.*; +import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementPresentation; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; +import com.intellij.codeInsight.lookup.TailTypeDecorator; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.psi.filters.getters.ExpectedTypesGetter; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -36,6 +40,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static com.intellij.patterns.PsiJavaPatterns.psiElement; + /** * @author peter */ @@ -47,11 +53,12 @@ class TypeArgumentCompletionProvider extends CompletionProvider pair = getTypeParameterInfo(context); if (pair == null) return; - final PsiType[] psiTypes = ExpectedTypesGetter.getExpectedTypes(context, false); - if (psiTypes.length > 0) { - for (PsiType type : psiTypes) { + ExpectedTypeInfo[] types = JavaSmartCompletionContributor.getExpectedTypes(parameters, false); + if (types.length > 0) { + for (ExpectedTypeInfo info : types) { + PsiType type = info.getType(); if (type instanceof PsiClassType) { - fillExpectedTypeArgs(resultSet, context, pair.first, pair.second, ((PsiClassType)type).resolveGenerics()); + fillExpectedTypeArgs(resultSet, context, pair.first, pair.second, ((PsiClassType)type).resolveGenerics(), info.getTailType()); } } } else { @@ -63,7 +70,7 @@ class TypeArgumentCompletionProvider extends CompletionProvider() { - @Override - public void renderElement(LookupElement element, LookupElementPresentation presentation) { - typeItems.get(0).renderElement(presentation); - presentation.setItemText(StringUtil.join(typeItems, new Function() { - @Override - public String fun(PsiTypeLookupItem item) { - return item.getLookupString(); - } - }, ", ")); - presentation.setTailText(null); - presentation.setTypeText(null); - } - }).setInsertHandler(new InsertHandler() { - @Override - public void handleInsert(InsertionContext context, LookupElement item) { - context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset()); - for (int i = 0; i < typeItems.size(); i++) { - CompletionUtil.emulateInsertion(context, context.getTailOffset(), typeItems.get(i)); - getTail(i == typeItems.size() - 1).processTail(context.getEditor(), context.getTailOffset()); - } - context.setAddCompletionChar(false); - } - })); + resultSet.addElement(new TypeArgsLookupElement(typeItems, globalTail, ConstructorInsertHandler.hasConstructorParameters(actualClass, context))); } @Nullable @@ -184,4 +168,79 @@ class TypeArgumentCompletionProvider extends CompletionProvider myTypeItems; + private final TailType myGlobalTail; + private final boolean myHasParameters; + + public TypeArgsLookupElement(List typeItems, TailType globalTail, boolean hasParameters) { + myTypeItems = typeItems; + myGlobalTail = globalTail; + myHasParameters = hasParameters; + myLookupString = StringUtil.join(myTypeItems, new Function() { + @Override + public String fun(PsiTypeLookupItem item) { + return item.getLookupString(); + } + }, ", "); + } + + @NotNull + @Override + public Object getObject() { + return myTypeItems.get(0).getObject(); + } + + @NotNull + @Override + public String getLookupString() { + return myLookupString; + } + + @Override + public void renderElement(LookupElementPresentation presentation) { + myTypeItems.get(0).renderElement(presentation); + presentation.setItemText(getLookupString()); + presentation.setTailText(null); + presentation.setTypeText(null); + } + + @Override + public void handleInsert(InsertionContext context) { + context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset()); + for (int i = 0; i < myTypeItems.size(); i++) { + CompletionUtil.emulateInsertion(context, context.getTailOffset(), myTypeItems.get(i)); + context.setTailOffset(getTail(i == myTypeItems.size() - 1).processTail(context.getEditor(), context.getTailOffset())); + } + context.setAddCompletionChar(false); + + context.commitDocument(); + + PsiElement leaf = context.getFile().findElementAt(context.getTailOffset() - 1); + if (psiElement().withParents(PsiReferenceParameterList.class, PsiJavaCodeReferenceElement.class, PsiNewExpression.class) + .accepts(leaf)) { + ParenthesesInsertHandler.getInstance(myHasParameters).handleInsert(context, this); + myGlobalTail.processTail(context.getEditor(), context.getTailOffset()); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TypeArgsLookupElement element = (TypeArgsLookupElement)o; + + if (!myTypeItems.equals(element.myTypeItems)) return false; + + return true; + } + + @Override + public int hashCode() { + return myTypeItems.hashCode(); + } + } } diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java index 2c3c66313e77..d2c7713aa4d4 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java @@ -1,5 +1,5 @@ -class HashMap {} +import java.util.HashMap; public class A { - private HashMap m = new HashMap(); + private HashMap m = new HashMap(); } diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java index 5e62309ae3d4..31ec5002ce6b 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java @@ -1,4 +1,4 @@ -class HashMap {} +import java.util.HashMap; public class A { private HashMap m = new HashMap<>(); diff --git a/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after12.java b/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after12.java index 052d2656908d..9a81b52d85c8 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after12.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after12.java @@ -1,4 +1,4 @@ class Test { - Test test = new Test + Test test = new Test(); } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java b/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java index aa55d681d903..5d8f893473e0 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java @@ -1,3 +1,3 @@ class AAAAA{ - AAAAA asd = new AAAAA + AAAAA asd = new AAAAA(); } \ No newline at end of file From e3833484986c8ecb78aeae3c3cff6ad31fba914c Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 9 Mar 2012 23:16:01 +0400 Subject: [PATCH 24/44] IDEA-26763 Auto-complete Generics on the RHS (now in basic completion as well) --- .../completion/JavaCompletionContributor.java | 4 ++++ .../completion/JavaSmartCompletionContributor.java | 5 ++++- .../completion/TypeArgumentCompletionProvider.java | 9 +++++++-- .../completion/normal/SuggestAllTypeArguments.java | 5 +++++ .../completion/normal/SuggestAllTypeArguments_after.java | 5 +++++ .../completion/smartType/ExcessiveTail-out.java | 2 +- .../codeInsight/completion/NormalCompletionTest.groovy | 9 +++++++++ 7 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments_after.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index a45001de281d..c0b0f557e958 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -210,6 +210,10 @@ public class JavaCompletionContributor extends CompletionContributor { return; } + if (JavaSmartCompletionContributor.IN_TYPE_ARGS.accepts(position)) { + new TypeArgumentCompletionProvider(false).addCompletions(parameters, new ProcessingContext(), result); + } + final InheritorsHolder inheritors = new InheritorsHolder(position, result); if (JavaSmartCompletionContributor.AFTER_NEW.accepts(position)) { new JavaInheritorsGetter(ConstructorInsertHandler.BASIC_INSTANCE).generateVariants(parameters, result.getPrefixMatcher(), inheritors); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index 3034d343843d..7af1b6edf7c5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.*; import com.intellij.codeInsight.lookup.*; import com.intellij.openapi.util.Key; import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PsiElementPattern; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.filters.ElementExtractorFilter; @@ -86,6 +87,8 @@ public class JavaSmartCompletionContributor extends CompletionContributor { static final ElementPattern INSIDE_TYPECAST_EXPRESSION = psiElement().withParent( psiElement(PsiReferenceExpression.class).afterLeaf( psiElement().withText(")").withParent(PsiTypeCastExpression.class))); + static final PsiElementPattern.Capture IN_TYPE_ARGS = + psiElement().inside(psiElement(PsiReferenceParameterList.class)); @Nullable private static ElementFilter getReferenceFilter(PsiElement element) { @@ -283,7 +286,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } }); - extend(CompletionType.SMART, psiElement().inside(psiElement(PsiReferenceParameterList.class)), new TypeArgumentCompletionProvider()); + extend(CompletionType.SMART, IN_TYPE_ARGS, new TypeArgumentCompletionProvider(true)); extend(CompletionType.SMART, AFTER_NEW, new JavaInheritorsGetter(ConstructorInsertHandler.SMART_INSTANCE)); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java index f074a9b140c4..ec1b392d96ff 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java @@ -46,6 +46,11 @@ import static com.intellij.patterns.PsiJavaPatterns.psiElement; * @author peter */ class TypeArgumentCompletionProvider extends CompletionProvider { + private final boolean mySmart; + + TypeArgumentCompletionProvider(boolean smart) { + mySmart = smart; + } protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) { final PsiElement context = parameters.getPosition(); @@ -58,10 +63,10 @@ class TypeArgumentCompletionProvider extends CompletionProvider m = new HashMap>() +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments_after.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments_after.java new file mode 100644 index 000000000000..e1350895943c --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments_after.java @@ -0,0 +1,5 @@ +import java.util.HashMap; + +public class A { + private HashMap m = new HashMap() +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/ExcessiveTail-out.java b/java/java-tests/testData/codeInsight/completion/smartType/ExcessiveTail-out.java index 2c3c66313e77..c3c03a12bc15 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/ExcessiveTail-out.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/ExcessiveTail-out.java @@ -1,5 +1,5 @@ class HashMap {} public class A { - private HashMap m = new HashMap(); + private HashMap m = new HashMap(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 3de5d0e61add..fc87669f19bb 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1315,4 +1315,13 @@ public class ListUtils { checkResult() } + public void testSuggestAllTypeArguments() { + configure() + assert 'String, String' == lookup.items[1].lookupString + lookup.currentItem = lookup.items[1] + type '\n' + checkResult() + + } + } From dcf1019419b0ab4c41fc1590d694029b3a114b85 Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 10 Mar 2012 00:46:46 +0400 Subject: [PATCH 25/44] IDEA-52159 Closure folding problem when closure method is not in direct super class --- .../folding/impl/JavaFoldingBuilder.java | 3 +- .../folding/JavaFoldingTest.groovy | 38 +++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java index 75320bf17347..34305ef9bc58 100644 --- a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java +++ b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.folding.impl; import com.intellij.codeInsight.folding.JavaCodeFoldingSettings; +import com.intellij.codeInsight.generation.OverrideImplementUtil; import com.intellij.lang.ASTNode; import com.intellij.lang.folding.CustomFoldingBuilder; import com.intellij.lang.folding.FoldingDescriptor; @@ -698,7 +699,7 @@ public class JavaFoldingBuilder extends CustomFoldingBuilder implements DumbAwar } } - return false; + return !OverrideImplementUtil.getMethodSignaturesToImplement(baseClass).isEmpty(); } private static boolean addToFold(List list, PsiElement elementToFold, Document document, boolean allowOneLiners) { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy index a4c54b800d8c..3b48d5e41fd3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -17,13 +17,12 @@ package com.intellij.codeInsight.folding; import com.intellij.codeInsight.folding.impl.CodeFoldingManagerImpl -import com.intellij.openapi.application.ex.PathManagerEx -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import com.intellij.codeInsight.folding.impl.JavaCodeFoldingSettingsImpl -import com.intellij.openapi.editor.impl.FoldingModelImpl import com.intellij.find.FindManager -import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.application.ex.PathManagerEx +import com.intellij.openapi.editor.impl.FoldingModelImpl import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase /** * @author Denis Zhdanov @@ -137,6 +136,37 @@ class Test { assertTrue closureEndFold.expanded } + public void "test closure folding when an abstract method is not in the direct superclass"() { + myFoldingSettings.COLLAPSE_CLOSURES = true + def text = """\ +public abstract class AroundTemplateMethod { + public abstract T execute(); +} +private static abstract class SetupTimer extends AroundTemplateMethod { +} +class Test { + void test() { + new SetupTimer() { + public Integer execute() { + return 0; + } + }; + } +} +""" + + configure text + def foldingModel = myFixture.editor.foldingModel as FoldingModelImpl + def closureStartFold = foldingModel.getCollapsedRegionAtOffset(text.indexOf("")) + assertNotNull closureStartFold + assertFalse closureStartFold.expanded + + assertNotNull closureStartFold.group + def closureFolds = foldingModel.getGroupedRegions(closureStartFold.group) + assertNotNull closureFolds + assertEquals(2, closureFolds.size()) + } + public void testFindInFolding() { def text = """\ class Test { From 59f53b3a942049b3ad002cab4aba76f51375c30b Mon Sep 17 00:00:00 2001 From: irengrig Date: Sat, 10 Mar 2012 03:59:39 +0400 Subject: [PATCH 26/44] IDEA-82331 Subversion: Incoming changes are not shown --- .../vcs/changes/committed/CommittedChangesCache.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java index 1c784afe91a3..c850c88d6820 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java @@ -599,7 +599,7 @@ public class CommittedChangesCache implements PersistentStateComponent receivedChanges) { - final ArrayList listCopy = receivedChanges == null ? null : new ArrayList(receivedChanges); + final Collection changes = receivedChanges == null ? myCachedIncomingChangeLists : receivedChanges; + if (changes == null) { + final List lists = loadIncomingChanges(false); + myBus.syncPublisher(COMMITTED_TOPIC).incomingChangesUpdated(new ArrayList(lists)); + return; + } + final ArrayList listCopy = new ArrayList(changes); myBus.syncPublisher(COMMITTED_TOPIC).incomingChangesUpdated(listCopy); } From 232f2020ff145753c3331df224fa28333c5e4691 Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Sat, 10 Mar 2012 10:47:30 +0400 Subject: [PATCH 27/44] Flex project structure: correctly navigate to module libraries from Project view (IDEA-82292) --- .../ProjectStructureConfigurable.java | 18 +------- .../ModuleStructureConfigurable.java | 45 +++++++++++++++---- .../projectRoot/ModuleStructureExtension.java | 11 +++++ 3 files changed, 49 insertions(+), 25 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java index 7988292deeaa..6933ecdf998f 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java @@ -20,7 +20,6 @@ import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleConfigurationEditor; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.options.BaseConfigurable; import com.intellij.openapi.options.Configurable; @@ -453,22 +452,7 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se } public ActionCallback selectOrderEntry(@NotNull final Module module, @Nullable final OrderEntry orderEntry) { - return select(module.getName(), null, true).doWhenDone(new Runnable() { - public void run() { - final MasterDetailsComponent.MyNode node = ModuleStructureConfigurable.getInstance(myProject).findModuleNode(module); - if (node != null) { - ModuleConfigurable moduleConfigurable = (ModuleConfigurable)node.getConfigurable(); - ModuleEditor moduleEditor = moduleConfigurable.getModuleEditor(); - moduleEditor.selectEditor(ClasspathEditor.NAME); - if (orderEntry != null) { - ModuleConfigurationEditor editor = moduleEditor.getEditor(ClasspathEditor.NAME); - if (editor instanceof ClasspathEditor) { - ((ClasspathEditor)editor).selectOrderEntry(orderEntry); - } - } - } - } - }); + return ModuleStructureConfigurable.getInstance(myProject).selectOrderEntry(module, orderEntry); } public ActionCallback navigateTo(@Nullable final Place place, final boolean requestFocus) { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java index 1ea708581f52..c1e9408f5c84 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java @@ -30,10 +30,7 @@ import com.intellij.ide.util.projectWizard.ProjectWizardUtil; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.module.ModifiableModuleModel; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.module.*; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; @@ -43,16 +40,16 @@ import com.intellij.openapi.roots.impl.ClonableOrderEntry; import com.intellij.openapi.roots.impl.ProjectRootManagerImpl; import com.intellij.openapi.roots.impl.RootModelImpl; import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.ui.configuration.ClasspathEditor; import com.intellij.openapi.roots.ui.configuration.ModuleEditor; import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; +import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.LibraryProjectStructureElement; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureDaemonAnalyzer; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; -import com.intellij.openapi.ui.DialogBuilder; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.NamedConfigurable; +import com.intellij.openapi.ui.*; +import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.NullableComputable; @@ -429,6 +426,38 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple return "reference.settingsdialog.project.structure.module"; } + public ActionCallback selectOrderEntry(@NotNull final Module module, @Nullable final OrderEntry orderEntry) { + for (final ModuleStructureExtension extension : ModuleStructureExtension.EP_NAME.getExtensions()) { + final ActionCallback callback = extension.selectOrderEntry(module, orderEntry); + if (callback != null) { + return callback; + } + } + + Place p = new Place(); + p.putPath(ProjectStructureConfigurable.CATEGORY, this); + Runnable r = null; + + final MasterDetailsComponent.MyNode node = findModuleNode(module); + if (node != null) { + p.putPath(TREE_OBJECT, module); + p.putPath(ModuleEditor.SELECTED_EDITOR_NAME, ClasspathEditor.NAME); + r = new Runnable() { + public void run() { + if (orderEntry != null) { + ModuleEditor moduleEditor = ((ModuleConfigurable)node.getConfigurable()).getModuleEditor(); + ModuleConfigurationEditor editor = moduleEditor.getEditor(ClasspathEditor.NAME); + if (editor instanceof ClasspathEditor) { + ((ClasspathEditor)editor).selectOrderEntry(orderEntry); + } + } + } + }; + } + final ActionCallback result = ProjectStructureConfigurable.getInstance(myProject).navigateTo(p, true); + return r != null ? result.doWhenDone(r) : result; + } + public static ModuleStructureConfigurable getInstance(final Project project) { return ServiceManager.getService(project, ModuleStructureConfigurable.class); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureExtension.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureExtension.java index e653fcccc923..dd17ab3ac246 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureExtension.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureExtension.java @@ -5,9 +5,12 @@ import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.ui.MasterDetailsComponent; import com.intellij.openapi.ui.NamedConfigurable; +import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.NullableComputable; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -71,4 +74,12 @@ public abstract class ModuleStructureExtension { public Comparator getNodeComparator() { return null; } + + /** + * @return callback or null if not handled + */ + @Nullable + public ActionCallback selectOrderEntry(@NotNull final Module module, @Nullable final OrderEntry entry) { + return null; + } } From c0d918dee80a7ad900434b2dbaeb0667f9e5be5a Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 10 Mar 2012 12:36:29 +0400 Subject: [PATCH 28/44] fix NPE --- .../arguments/GrArgumentLabelImpl.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java index fa9ba5accff3..648ffc6fcf2d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java @@ -44,6 +44,8 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import java.util.Map; + /** * @author ilyas */ @@ -79,13 +81,14 @@ public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgum String labelName = getName(); - NamedArgumentDescriptor descr = - GroovyNamedArgumentProvider.getNamedArgumentsFromAllProviders(call, labelName, false).get(labelName); - - if (descr != null) { - PsiPolyVariantReference res = descr.createReference(this); - if (res != null) { - return res; + Map providers = GroovyNamedArgumentProvider.getNamedArgumentsFromAllProviders(call, labelName, false); + if (providers != null) { + NamedArgumentDescriptor descr = providers.get(labelName); + if (descr != null) { + PsiPolyVariantReference res = descr.createReference(this); + if (res != null) { + return res; + } } } From 1570f401b78c064daa19c8dee71469ba40882a75 Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 10 Mar 2012 14:02:30 +0400 Subject: [PATCH 29/44] IDEA-81667 Good code is red for static initializers in Groovy --- .../typeDefinitions/members/ClassMember.java | 1 + .../groovy/lang/parser/TypesParsingTest.java | 1 + .../groovy/types/staticInitializer.test | 73 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 plugins/groovy/testdata/parsing/groovy/types/staticInitializer.test diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ClassMember.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ClassMember.java index 2bdebbfd0574..79fe633b88d5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ClassMember.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ClassMember.java @@ -53,6 +53,7 @@ public class ClassMember implements GroovyElementTypes { PsiBuilder.Marker initMarker = builder.mark(); PsiBuilder.Marker modMarker = builder.mark(); ParserUtils.getToken(builder, kSTATIC); + ParserUtils.getToken(builder, mNLS); if (mLCURLY == builder.getTokenType()) { modMarker.done(MODIFIERS); if (OpenOrClosableBlock.parseOpenBlock(builder, parser)) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/TypesParsingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/TypesParsingTest.java index 3e21513f9f32..c036ab091810 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/TypesParsingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/TypesParsingTest.java @@ -34,5 +34,6 @@ public class TypesParsingTest extends GroovyParsingTestCase { public void testInnerEnum() throws Throwable { doTest(); } public void testNewlineBeforeClassBrace() throws Throwable { doTest(); } public void testNewlineBeforeExtends() throws Throwable { doTest(); } + public void testStaticInitializer() throws Throwable { doTest(); } } \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/types/staticInitializer.test b/plugins/groovy/testdata/parsing/groovy/types/staticInitializer.test new file mode 100644 index 000000000000..d0af3cac82e1 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/types/staticInitializer.test @@ -0,0 +1,73 @@ +class StaticDemo { + static + { + println "Demo" + } + + public static void main(String[] args) + { + + } +} +----- +Groovy script + Class definition + Modifiers + + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(identifier)('StaticDemo') + PsiWhiteSpace(' ') + Type definition body + PsiElement({)('{') + PsiWhiteSpace('\n ') + Class initializer + Modifiers + PsiElement(static)('static') + PsiElement(new line)('\n ') + Open block + PsiElement({)('{') + PsiWhiteSpace('\n ') + Call expression + Reference expression + PsiElement(identifier)('println') + PsiWhiteSpace(' ') + Command arguments + Literal + PsiElement(Gstring)('"Demo"') + PsiElement(new line)('\n ') + PsiElement(})('}') + PsiElement(new line)('\n\n ') + Method + Modifiers + PsiElement(public)('public') + PsiWhiteSpace(' ') + PsiElement(static)('static') + PsiWhiteSpace(' ') + Built in type + PsiElement(void)('void') + PsiWhiteSpace(' ') + PsiElement(identifier)('main') + PsiElement(()('(') + Parameter list + Parameter + Modifiers + + Array type + Type element + Reference element + PsiElement(identifier)('String') + PsiElement([)('[') + PsiElement(])(']') + PsiWhiteSpace(' ') + PsiElement(identifier)('args') + PsiElement())(')') + PsiElement(new line)('\n ') + Throw clause + + Open block + PsiElement({)('{') + PsiWhiteSpace('\n\n ') + PsiElement(})('}') + PsiElement(new line)('\n') + PsiElement(})('}') \ No newline at end of file From ba96ab71a6753b479042afa0f9b566645274dc5a Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 10 Mar 2012 14:46:10 +0400 Subject: [PATCH 30/44] IDEA-60608 Groovy: Code Completion for "in" keyword is missing --- .../lang/completion/GroovyCompletionData.java | 14 +++++++++++++- .../groovy/completion/GroovyAutoPopupTest.groovy | 1 + .../groovy/completion/GroovyCompletionTest.groovy | 5 +++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java index 0cbe9c32803f..8a71e69e7784 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java @@ -25,6 +25,7 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.codeInsight.lookup.TailTypeDecorator; import com.intellij.lang.ASTNode; +import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.*; import com.intellij.psi.templateLanguages.OuterLanguageElement; @@ -42,6 +43,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation. import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrTraditionalForClause; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; @@ -96,7 +98,10 @@ public class GroovyCompletionData { result.addElement(keyword("as", TailType.HUMBLE_SPACE_BEFORE_WORD)); } - if (isInfixOperatorPosition(position)) { + if (isAfterForParameter(position)) { + addKeywords(result, true, "in"); + } + else if (isInfixOperatorPosition(position)) { addKeywords(result, true, "in", PsiKeyword.INSTANCEOF); } else if (suggestThrows(position)) { result.addElement(keyword(PsiKeyword.THROWS, TailType.INSERT_SPACE)); @@ -135,6 +140,13 @@ public class GroovyCompletionData { } } + private static boolean isAfterForParameter(PsiElement position) { + ElementPattern forParameter = + psiElement().withParents(GrParameter.class, GrTraditionalForClause.class, GrForStatement.class); + return psiElement().withParent(GrReferenceExpression.class).afterLeaf(forParameter).accepts(position) || + forParameter.accepts(position) && psiElement().afterLeaf(psiElement(GroovyTokenTypes.mIDENT)).accepts(position); + } + public static void addModifiers(PsiElement position, CompletionResultSet result) { PsiClass scope = PsiTreeUtil.getParentOfType(position, PsiClass.class); PsiModifierList modifierList = ModifierChooser.findModifierList(position); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy index 57e82942aeff..4eda27241e6a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy @@ -184,6 +184,7 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase { assert !lookup type 'c' assert !lookup.focused + assert 'char' in myFixture.lookupElementStrings assert myFixture.editor.document.text.contains('for(final c)') type ' in c' assert lookup.focused diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index 739fa2d75186..475f214ad1d4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -1188,4 +1188,9 @@ new Base().fiex''') assert myFixture.lookupElementStrings == ['field1'] } + public void testForIn() { + assert doContainsTest('in', 'for (int i i') + assert doContainsTest('in', 'for (i i') + } + } \ No newline at end of file From cf531ce169e1552c28f25f0c96f0135839b21250 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 9 Mar 2012 14:12:12 +0400 Subject: [PATCH 31/44] Logging collecting info to push procedure. Trying to catch the bug when pressing "Push" before completely loading the list of commits to push, resulted in "Nothing to push". --- .../src/git4idea/push/GitPushDialog.java | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/plugins/git4idea/src/git4idea/push/GitPushDialog.java b/plugins/git4idea/src/git4idea/push/GitPushDialog.java index dc42b4c33b94..b8994e4840dd 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushDialog.java +++ b/plugins/git4idea/src/git4idea/push/GitPushDialog.java @@ -27,6 +27,7 @@ import com.intellij.util.Consumer; import com.intellij.util.ui.UIUtil; import git4idea.GitBranch; import git4idea.GitUtil; +import git4idea.history.browser.GitCommit; import git4idea.repo.GitRemote; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; @@ -58,7 +59,7 @@ public class GitPushDialog extends DialogWrapper { private final Object COMMITS_LOADING_LOCK = new Object(); private final GitManualPushToBranch myRefspecPanel; private final AtomicReference myDestBranchInfoOnRefresh = new AtomicReference(); - + private final boolean myPushPossible; public GitPushDialog(@NotNull Project project) { @@ -115,14 +116,14 @@ public class GitPushDialog extends DialogWrapper { private void loadCommitsInBackground() { myLoadingPanel.startLoading(); - + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { public void run() { final AtomicReference error = new AtomicReference(); synchronized (COMMITS_LOADING_LOCK) { error.set(collectInfoToPush()); } - + final Pair remoteAndBranch = getRemoteAndTrackedBranchForCurrentBranch(); UIUtil.invokeLaterIfNeeded(new Runnable() { @Override @@ -175,8 +176,11 @@ public class GitPushDialog extends DialogWrapper { @Nullable private String collectInfoToPush() { try { + LOG.info("collectInfoToPush..."); myPushSpecs = pushSpecsForCurrentOrEnteredBranches(); + LOG.info("PushSpecsForCurrentOrEnteredBranches: " + myPushSpecs); myGitCommitsToPush = myPusher.collectCommitsToPush(myPushSpecs); + LOG.info("Collected commits to push: " + logMessageForCommits(myGitCommitsToPush)); return null; } catch (VcsException e) { @@ -185,7 +189,15 @@ public class GitPushDialog extends DialogWrapper { return e.getMessage(); } } - + + private static String logMessageForCommits(GitCommitsByRepoAndBranch commitsToPush) { + StringBuilder logMessage = new StringBuilder(); + for (GitCommit commit : commitsToPush.getAllCommits()) { + logMessage.append(commit.getShortHash()); + } + return logMessage.toString(); + } + private Map pushSpecsForCurrentOrEnteredBranches() throws VcsException { Map defaultSpecs = new HashMap(); for (GitRepository repository : myRepositories) { @@ -220,7 +232,7 @@ public class GitPushDialog extends DialogWrapper { } tracked = manualBranch; } - + GitPushSpec pushSpec = new GitPushSpec(remote, currentBranch, tracked); defaultSpecs.put(repository, pushSpec); } @@ -260,19 +272,23 @@ public class GitPushDialog extends DialogWrapper { // waiting for commit list loading, because this information is needed to correctly handle rejected push situation and correctly // notify about pushed commits // TODO optimize: don't refresh: information about pushed commits can be achieved from the successful push output + LOG.info("getPushInfo"); synchronized (COMMITS_LOADING_LOCK) { GitCommitsByRepoAndBranch selectedCommits; if (myGitCommitsToPush == null) { + LOG.info("getPushInfo | myGitCommitsToPush == null. collecting..."); collectInfoToPush(); selectedCommits = myGitCommitsToPush; } else { if (refreshNeeded()) { + LOG.info("getPushInfo | refresh is needed, collecting..."); collectInfoToPush(); } Collection selectedRepositories = myListPanel.getSelectedRepositories(); selectedCommits = myGitCommitsToPush.retainAll(selectedRepositories); } + LOG.info("getPushInfo | selectedCommits: " + logMessageForCommits(selectedCommits)); return new GitPushInfo(selectedCommits, myPushSpecs); } } From ace9f24bb31c0a51a7bb025a19d9a05a86bbe5c9 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sat, 10 Mar 2012 13:00:11 +0400 Subject: [PATCH 32/44] small optimization: to check if there were any remote changes, it's enough to git rev-list -1. --- plugins/git4idea/src/git4idea/update/GitUpdater.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/update/GitUpdater.java b/plugins/git4idea/src/git4idea/update/GitUpdater.java index 33e3cd13d546..d5ef3ce7923e 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdater.java @@ -161,8 +161,9 @@ public abstract class GitUpdater { } protected boolean hasRemoteChanges(@NotNull String currentBranch, @NotNull String remoteBranch) throws VcsException { - GitSimpleHandler handler = new GitSimpleHandler(myProject, myRoot, GitCommand.LOG); + GitSimpleHandler handler = new GitSimpleHandler(myProject, myRoot, GitCommand.REV_LIST); handler.setNoSSH(true); + handler.addParameters("-1"); handler.addParameters(currentBranch + ".." + remoteBranch); String output = handler.run(); return output != null && !output.isEmpty(); From fd1cdddce318664f48881fe927b70002da64e6e3 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sat, 10 Mar 2012 13:33:43 +0400 Subject: [PATCH 33/44] Initialize GitRepositoryManager in a DumbAwareRunnable - it should be already available while indexing. +cosmetics: fix convert to local warning. --- .../git4idea/src/git4idea/repo/GitRepositoryManager.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java index bb160315d24b..e908f177742c 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java @@ -20,6 +20,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootEvent; import com.intellij.openapi.roots.ModuleRootListener; @@ -53,7 +54,6 @@ public final class GitRepositoryManager extends AbstractProjectComponent impleme private final @NotNull AbstractVcs myVcs; private final @NotNull ProjectLevelVcsManager myVcsManager; - private final @NotNull PlatformFacade myPlatformFacade; private final Map myRepositories = new HashMap(); private final Set myListeners = new HashSet(); @@ -67,15 +67,14 @@ public final class GitRepositoryManager extends AbstractProjectComponent impleme public GitRepositoryManager(@NotNull Project project, @NotNull PlatformFacade platformFacade) { super(project); - myPlatformFacade = platformFacade; myVcsManager = ProjectLevelVcsManager.getInstance(myProject); - myVcs = myPlatformFacade.getVcs(myProject); + myVcs = platformFacade.getVcs(myProject); } @Override public void initComponent() { Disposer.register(myProject, this); - StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() { + StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() { @Override public void run() { final MessageBus messageBus = myProject.getMessageBus(); From 753b3ced72e44dfbf495b32574469c2574adb558 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sat, 10 Mar 2012 14:21:39 +0400 Subject: [PATCH 34/44] Fix pressing "Push" before completely loading the list of commits Selected repositories are gotten from GitPushLog, which can be not constructed yet. In that case use all repositories. --- .../src/git4idea/push/GitPushDialog.java | 7 +++-- .../src/git4idea/push/GitPushLog.java | 27 ++++++++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/plugins/git4idea/src/git4idea/push/GitPushDialog.java b/plugins/git4idea/src/git4idea/push/GitPushDialog.java index b8994e4840dd..079d0c7d987a 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushDialog.java +++ b/plugins/git4idea/src/git4idea/push/GitPushDialog.java @@ -178,14 +178,13 @@ public class GitPushDialog extends DialogWrapper { try { LOG.info("collectInfoToPush..."); myPushSpecs = pushSpecsForCurrentOrEnteredBranches(); - LOG.info("PushSpecsForCurrentOrEnteredBranches: " + myPushSpecs); myGitCommitsToPush = myPusher.collectCommitsToPush(myPushSpecs); - LOG.info("Collected commits to push: " + logMessageForCommits(myGitCommitsToPush)); + LOG.info("collectInfoToPush | Collected commits to push: " + logMessageForCommits(myGitCommitsToPush)); return null; } catch (VcsException e) { myGitCommitsToPush = GitCommitsByRepoAndBranch.empty(); - LOG.error("Couldn't collect commits to push. Push spec: " + myPushSpecs, e); + LOG.error("collectInfoToPush | Couldn't collect commits to push. Push spec: " + myPushSpecs, e); return e.getMessage(); } } @@ -272,7 +271,7 @@ public class GitPushDialog extends DialogWrapper { // waiting for commit list loading, because this information is needed to correctly handle rejected push situation and correctly // notify about pushed commits // TODO optimize: don't refresh: information about pushed commits can be achieved from the successful push output - LOG.info("getPushInfo"); + LOG.info("getPushInfo start"); synchronized (COMMITS_LOADING_LOCK) { GitCommitsByRepoAndBranch selectedCommits; if (myGitCommitsToPush == null) { diff --git a/plugins/git4idea/src/git4idea/push/GitPushLog.java b/plugins/git4idea/src/git4idea/push/GitPushLog.java index f8ada332cb7b..1524ebc2aeeb 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushLog.java +++ b/plugins/git4idea/src/git4idea/push/GitPushLog.java @@ -61,6 +61,7 @@ class GitPushLog extends JPanel implements TypeSafeDataProvider { private final DefaultTreeModel myTreeModel; private final CheckedTreeNode myRootNode; private final ReentrantReadWriteLock TREE_CONSTRUCTION_LOCK = new ReentrantReadWriteLock(); + private boolean myTreeWasConstructed; private final MyTreeCellRenderer myTreeCellRenderer; GitPushLog(@NotNull Project project, @NotNull Collection repositories, @NotNull final Consumer checkboxListener) { @@ -166,6 +167,7 @@ class GitPushLog extends JPanel implements TypeSafeDataProvider { myTree.setModel(myTreeModel); // TODO: why doesn't it repaint otherwise? TreeUtil.expandAll(myTree); selectFirstCommit(); + myTreeWasConstructed = true; } finally { TREE_CONSTRUCTION_LOCK.writeLock().unlock(); @@ -259,23 +261,28 @@ class GitPushLog extends JPanel implements TypeSafeDataProvider { try { TREE_CONSTRUCTION_LOCK.readLock().lock(); // wait for tree to be constructed - Collection selectedRepositories = new ArrayList(myAllRepositories.size()); - if (myRootNode.getChildCount() == 0) { // the method is requested before tree construction began => returning all repos. + if (!myTreeWasConstructed) { return myAllRepositories; } + else { + Collection selectedRepositories = new ArrayList(myAllRepositories.size()); + if (myRootNode.getChildCount() == 0) { // the method is requested before tree construction began => returning all repos. + return myAllRepositories; + } - for (int i = 0; i < myRootNode.getChildCount(); i++) { - TreeNode child = myRootNode.getChildAt(i); - if (child instanceof CheckedTreeNode) { - CheckedTreeNode node = (CheckedTreeNode)child; - if (node.isChecked()) { - if (node.getUserObject() instanceof GitRepository) { - selectedRepositories.add((GitRepository)node.getUserObject()); + for (int i = 0; i < myRootNode.getChildCount(); i++) { + TreeNode child = myRootNode.getChildAt(i); + if (child instanceof CheckedTreeNode) { + CheckedTreeNode node = (CheckedTreeNode)child; + if (node.isChecked()) { + if (node.getUserObject() instanceof GitRepository) { + selectedRepositories.add((GitRepository)node.getUserObject()); + } } } } + return selectedRepositories; } - return selectedRepositories; } finally { TREE_CONSTRUCTION_LOCK.readLock().unlock(); From da06fb2951b830fbbf33db5a7c700811eb0f1463 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sat, 10 Mar 2012 15:14:45 +0400 Subject: [PATCH 35/44] Fix 'git fetch --prune' deleting all remote refs. Before Git 1.7.7.2 'git fetch --prune origin master' used to remove all remote references. This was fixed in 1.7.7.2. For the sake of simplicity we are not going to call '--prune' for the older Gits. Other way would be to call 'git remote prune origin' for older Gits, but this auto-prune feature doesn't seem to be important enough for such effort. --- .../git4idea/src/git4idea/config/GitVersionSpecialty.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java b/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java index 3c3f384249b2..fbb0826f1fd8 100644 --- a/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java +++ b/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java @@ -73,10 +73,15 @@ public enum GitVersionSpecialty { } }, + /** + * {@code git fetch --prune} is actually supported since 1.7.0, + * but before 1.7.7.2 calling {@code git fetch --prune origin master} would delete all other references. + * This was fixed in {@code ed43de6ec35dfd4c4bd33ae9b5f2ebe38282209f} and added to the Git 1.7.7.2 release. + */ SUPPORTS_FETCH_PRUNE { @Override public boolean existsIn(@NotNull GitVersion version) { - return version.isLaterOrEqual(new GitVersion(1, 7, 0, 0)); + return version.isLaterOrEqual(new GitVersion(1, 7, 7, 2)); } }, From d1afa62d28d8e9becc2941c0d57d7a5d50a9afb7 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sat, 10 Mar 2012 15:56:42 +0400 Subject: [PATCH 36/44] Git fetch: update remote branch ref 'git fetch origin master' only updates the FETCH_HEAD without updating refs/remotes/origin/master. We don't read FETCH_HEAD for merging, preferring to call 'git log master..origin/master' to decide if we need to merge => updating the remote ref is necessary. Supply the full refspec to 'git fetch' to update the remote ref. --- .../src/git4idea/update/GitFetcher.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/plugins/git4idea/src/git4idea/update/GitFetcher.java b/plugins/git4idea/src/git4idea/update/GitFetcher.java index 2eb080ef59de..1891a93155d4 100644 --- a/plugins/git4idea/src/git4idea/update/GitFetcher.java +++ b/plugins/git4idea/src/git4idea/update/GitFetcher.java @@ -46,6 +46,9 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static git4idea.GitBranch.REFS_HEADS_PREFIX; +import static git4idea.GitBranch.REFS_REMOTES_PREFIX; + /** * @author Kirill Likhodedov */ @@ -158,10 +161,14 @@ public class GitFetcher { if (GitVersionSpecialty.SUPPORTS_FETCH_PRUNE.existsIn(myVcs.getVersion())) { h.addParameters("--prune"); } - h.addParameters(remote.getName()); + + String remoteName = remote.getName(); + h.addParameters(remoteName); if (branch != null) { - h.addParameters(branch); + branch = getRidOfPrefixIfExists(branch); + h.addParameters(REFS_HEADS_PREFIX + branch + ":" + REFS_REMOTES_PREFIX + remoteName + "/" + branch); } + final GitTask fetchTask = new GitTask(myProject, h, "Fetching..."); fetchTask.setProgressIndicator(myProgressIndicator); fetchTask.setProgressAnalyzer(new GitStandardProgressAnalyzer()); @@ -198,6 +205,13 @@ public class GitFetcher { return result.get(); } + private static String getRidOfPrefixIfExists(String branch) { + if (branch.startsWith(REFS_HEADS_PREFIX)) { + return branch.substring(REFS_HEADS_PREFIX.length()); + } + return branch; + } + @NotNull public Collection getErrors() { return myErrors; From 346cf29beb1a45029cc725d8d56cc8f7c926e7dc Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 10 Mar 2012 16:37:49 +0400 Subject: [PATCH 37/44] make custom file type lexer tests easir to write --- .../custom/CustomFileTypeLexerTest.groovy | 273 +++++++++++++++++- .../custom/CustomFileTypeLexerTestBase.java | 47 --- .../ide/highlighter/custom/JavaCodeTest.java | 130 --------- .../custom/PropertiesFileTest.java | 112 ------- .../intellij/testFramework/LexerTestCase.java | 2 +- 5 files changed, 260 insertions(+), 304 deletions(-) delete mode 100644 platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTestBase.java delete mode 100644 platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/JavaCodeTest.java delete mode 100644 platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/PropertiesFileTest.java diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy index 7311244aae15..a709c66bed81 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy @@ -15,15 +15,21 @@ */ package com.intellij.ide.highlighter.custom -import com.intellij.psi.tree.IElementType -import static com.intellij.psi.CustomHighlighterTokenType.* +import org.jetbrains.annotations.NonNls +import org.jetbrains.annotations.Nullable +import com.intellij.testFramework.LexerTestCase +import junit.framework.TestCase /** * @author peter */ -class CustomFileTypeLexerTest extends CustomFileTypeLexerTestBase { - @Override - protected SyntaxTable createSyntaxTable() { +class CustomFileTypeLexerTest extends TestCase { + + protected void doTest(SyntaxTable table, @NonNls String text, @Nullable String expected) { + assertEquals(expected, LexerTestCase.printTokens(text, 0, new CustomFileTypeLexer(table))); + } + + private SyntaxTable createGenericTable() { SyntaxTable table = new SyntaxTable(); table.lineComment = ';' @@ -40,20 +46,259 @@ class CustomFileTypeLexerTest extends CustomFileTypeLexerTestBase { } public void testSpacesInsideKeywords() { - checkTypesAndTokens('if length(variable)then return 1', - [KEYWORD_1, WHITESPACE, KEYWORD_1, CHARACTER, IDENTIFIER, CHARACTER, KEYWORD_1, WHITESPACE, KEYWORD_2, WHITESPACE, NUMBER] as IElementType[], - ['if', ' ', 'length', '(', 'variable', ')', 'then', ' ', 'return', ' ', '1'] as String[]) - + doTest createGenericTable(), 'if length(variable)then return 1', '''\ +KEYWORD_1 ('if') +WHITESPACE (' ') +KEYWORD_1 ('length') +CHARACTER ('(') +IDENTIFIER ('variable') +CHARACTER (')') +KEYWORD_1 ('then') +WHITESPACE (' ') +KEYWORD_2 ('return') +WHITESPACE (' ') +NUMBER ('1') +''' } public void testFortranComments() { - checkTypesAndTokens(''' + doTest createGenericTable(), ''' foo;noncomment ;comment ;noncomment -''', - [WHITESPACE, IDENTIFIER, PUNCTUATION, IDENTIFIER, WHITESPACE, LINE_COMMENT, WHITESPACE, PUNCTUATION, IDENTIFIER, WHITESPACE] as IElementType[], - ['\n', 'foo', ';', 'noncomment', '\n', ';comment', '\n ', ';', 'noncomment', '\n'] as String[]) - +''', '''\ +WHITESPACE ('\\n') +IDENTIFIER ('foo') +PUNCTUATION (';') +IDENTIFIER ('noncomment') +WHITESPACE ('\\n') +LINE_COMMENT (';comment') +WHITESPACE ('\\n ') +PUNCTUATION (';') +IDENTIFIER ('noncomment') +WHITESPACE ('\\n') +''' } + + private SyntaxTable createJavaSyntaxTable() { + SyntaxTable table = new SyntaxTable(); + + table.setLineComment("//"); + table.setStartComment("/*"); + table.setEndComment("*/"); + + table.setHexPrefix("0x"); + table.setNumPostfixChars("cfdle"); + + table.addKeyword1("package"); + table.addKeyword1("import"); + table.addKeyword1("this"); + table.addKeyword1("super"); + table.addKeyword1("public"); + table.addKeyword1("private"); + table.addKeyword1("protected"); + table.addKeyword1("null"); + table.addKeyword1("if"); + table.addKeyword1("else"); + table.addKeyword1("throws"); + table.addKeyword1("switch"); + table.addKeyword1("case"); + table.addKeyword1("break"); + table.addKeyword1("default"); + table.addKeyword1("continue"); + table.addKeyword1("goto"); + table.addKeyword1("boolean"); + table.addKeyword1("true"); + table.addKeyword1("false"); + table.addKeyword1("final"); + table.addKeyword1("class"); + table.addKeyword1("static"); + table.addKeyword1("final"); + table.addKeyword1("void"); + table.addKeyword1("int"); + table.addKeyword1("while"); + table.addKeyword1("new"); + table.addKeyword1("for"); + table.addKeyword1("byte"); + table.addKeyword1("float"); + table.addKeyword1("double"); + table.addKeyword1("short"); + table.addKeyword1("extends"); + table.addKeyword1("implements"); + table.addKeyword1("interface"); + table.addKeyword1("abstract"); + table.addKeyword1("char"); + table.addKeyword1("try"); + table.addKeyword1("catch"); + table.addKeyword1("finally"); + table.addKeyword1("synchronized"); + + return table; + } + + public void testParseSampleCode() { + doTest createJavaSyntaxTable(), "private some text f b g\n\n\n// 1\n public static void main(String[] args) {\n}\n-10 - 10\n\"dsfdfdf\"\n/* a\n *bc */", '''\ +KEYWORD_1 ('private') +WHITESPACE (' ') +IDENTIFIER ('some') +WHITESPACE (' ') +IDENTIFIER ('text') +WHITESPACE (' ') +IDENTIFIER ('f') +WHITESPACE (' ') +IDENTIFIER ('b') +WHITESPACE (' ') +IDENTIFIER ('g') +WHITESPACE ('\\n\\n\\n') +LINE_COMMENT ('// 1') +WHITESPACE ('\\n ') +KEYWORD_1 ('public') +WHITESPACE (' ') +KEYWORD_1 ('static') +WHITESPACE (' ') +KEYWORD_1 ('void') +WHITESPACE (' ') +IDENTIFIER ('main') +CHARACTER ('(') +IDENTIFIER ('String') +CHARACTER ('[') +CHARACTER (']') +WHITESPACE (' ') +IDENTIFIER ('args') +CHARACTER (')') +WHITESPACE (' ') +CHARACTER ('{') +WHITESPACE ('\\n') +CHARACTER ('}') +WHITESPACE ('\\n') +CHARACTER ('-') +NUMBER ('10') +WHITESPACE (' ') +CHARACTER ('-') +WHITESPACE (' ') +NUMBER ('10') +WHITESPACE ('\\n') +STRING ('"dsfdfdf"') +WHITESPACE ('\\n') +MULTI_LINE_COMMENT ('/* a\\n *bc */') +''' + } + + public void testBlockCommentStart() { + doTest createJavaSyntaxTable(), "/*", 'MULTI_LINE_COMMENT (\'/*\')\n' + } + + public void testLineCommentStart() { + doTest createJavaSyntaxTable(), "//", 'LINE_COMMENT (\'//\')\n' + } + + public void testEmpty() { + doTest createJavaSyntaxTable(), "", '' + } + + public void testSpace() { + doTest createJavaSyntaxTable(), " ", 'WHITESPACE (\' \')\n' + } + + public void testParseSampleCodeFromTo() { + String sampleCode = " int n=123;\n float z=1;"; + def lexer = new CustomFileTypeLexer(createJavaSyntaxTable()) + lexer.start(sampleCode, 5, 5); + assertEquals(lexer.getTokenType(), null); + lexer.start(sampleCode, 5, 6); + lexer.getTokenType(); + assertEquals(5, lexer.getTokenStart()); + assertEquals(6, lexer.getTokenEnd()); + assertEquals(6, lexer.getBufferEnd()); + } + + private SyntaxTable createPropTable() { + SyntaxTable table = new SyntaxTable(); + + table.setLineComment("#"); + table.setIgnoreCase(true); + + table.addKeyword1("value"); + table.addKeyword2("Value"); + table.setNumPostfixChars("LGH"); + return table; + } + + public void testSimple() { + doTest createPropTable(), "# Comment\n" + + "x.1.a=12.2L\n" + + " y.2.b=13.4 # comment\n" + + "VALUE value VaLuE Value1 17.00h 11.0k", '''\ +LINE_COMMENT ('# Comment') +WHITESPACE ('\\n') +IDENTIFIER ('x') +PUNCTUATION ('.') +NUMBER ('1') +PUNCTUATION ('.') +IDENTIFIER ('a') +CHARACTER ('=') +NUMBER ('12.2L') +WHITESPACE ('\\n ') +IDENTIFIER ('y') +PUNCTUATION ('.') +NUMBER ('2') +PUNCTUATION ('.') +IDENTIFIER ('b') +CHARACTER ('=') +NUMBER ('13.4') +WHITESPACE (' ') +LINE_COMMENT ('# comment') +WHITESPACE ('\\n') +KEYWORD_1 ('VALUE') +WHITESPACE (' ') +KEYWORD_1 ('value') +WHITESPACE (' ') +KEYWORD_1 ('VaLuE') +WHITESPACE (' ') +IDENTIFIER ('Value1') +WHITESPACE (' ') +NUMBER ('17.00h') +WHITESPACE (' ') +NUMBER ('11') +PUNCTUATION ('.') +NUMBER ('0') +IDENTIFIER ('k') +''' + } + + public void testNumber() { + doTest createPropTable(), "1.23=1.24", '''\ +NUMBER ('1.23') +CHARACTER ('=') +NUMBER ('1.24') +''' + } + + public void testPostfix() { + doTest createPropTable(), "abc 1.2ltext", '''\ +IDENTIFIER ('abc') +WHITESPACE (' ') +NUMBER ('1.2l') +IDENTIFIER ('text') +''' + } + + public void testWeird() { + doTest createPropTable(), "test.1.", '''\ +IDENTIFIER ('test') +PUNCTUATION ('.') +NUMBER ('1.') +''' + } + + public void testParenths() throws Exception { + doTest createPropTable(),"value(255)", '''\ +KEYWORD_1 ('value') +CHARACTER ('(') +NUMBER ('255') +CHARACTER (')') +''' + } + + } diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTestBase.java b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTestBase.java deleted file mode 100644 index 62d706d60cc4..000000000000 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTestBase.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.intellij.ide.highlighter.custom; - -import com.intellij.lexer.Lexer; -import com.intellij.psi.tree.IElementType; -import junit.framework.TestCase; - -/** - * @author dsl - */ -public abstract class CustomFileTypeLexerTestBase extends TestCase { - protected Lexer lexer; - - @Override - protected void setUp() throws Exception { - lexer = new CustomFileTypeLexer(createSyntaxTable()); - } - - protected abstract SyntaxTable createSyntaxTable(); - - protected void checkTypesAndTokens(String sampleCode, IElementType[] types, String[] matches) { - lexer.start(sampleCode); - assertEquals(types.length, matches.length); - - for (int i = 0; i < types.length; i++) { - assertEquals("Failed at index=" + i, types[i], lexer.getTokenType()); - assertEquals("Failed at index=" + i, matches[i], sampleCode.substring(lexer.getTokenStart(), lexer.getTokenEnd())); - lexer.advance(); - } - } - - protected void checkSameText(String sampleCode) { - lexer.start(sampleCode); - StringBuffer sb = new StringBuffer(); - String result; - while (lexer.getTokenType() != null) { - result = sampleCode.substring(lexer.getTokenStart(), lexer.getTokenEnd()); - sb.append(result); - lexer.advance(); - } - - assertEquals("Text created by lexer's output does not match the original text", sampleCode, sb.toString()); - } - - public void testNothing() throws Exception { - //TODO[dsl] Testcase fails if there's no any testcase. So I've added an empty one. - } -} diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/JavaCodeTest.java b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/JavaCodeTest.java deleted file mode 100644 index 44aa6b6f2311..000000000000 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/JavaCodeTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.intellij.ide.highlighter.custom; - -import com.intellij.psi.CustomHighlighterTokenType; -import com.intellij.psi.tree.IElementType; - -/** - * @author Yura Cangea - * @version 1.0 - */ -public class JavaCodeTest extends CustomFileTypeLexerTestBase { - - @Override - public SyntaxTable createSyntaxTable() { - SyntaxTable table = new SyntaxTable(); - - table.setLineComment("//"); - table.setStartComment("/*"); - table.setEndComment("*/"); - - table.setHexPrefix("0x"); - table.setNumPostfixChars("cfdle"); - - table.addKeyword1("package"); - table.addKeyword1("import"); - table.addKeyword1("this"); - table.addKeyword1("super"); - table.addKeyword1("public"); - table.addKeyword1("private"); - table.addKeyword1("protected"); - table.addKeyword1("null"); - table.addKeyword1("if"); - table.addKeyword1("else"); - table.addKeyword1("throws"); - table.addKeyword1("switch"); - table.addKeyword1("case"); - table.addKeyword1("break"); - table.addKeyword1("default"); - table.addKeyword1("continue"); - table.addKeyword1("goto"); - table.addKeyword1("boolean"); - table.addKeyword1("true"); - table.addKeyword1("false"); - table.addKeyword1("final"); - table.addKeyword1("class"); - table.addKeyword1("static"); - table.addKeyword1("final"); - table.addKeyword1("void"); - table.addKeyword1("int"); - table.addKeyword1("while"); - table.addKeyword1("new"); - table.addKeyword1("for"); - table.addKeyword1("byte"); - table.addKeyword1("float"); - table.addKeyword1("double"); - table.addKeyword1("short"); - table.addKeyword1("extends"); - table.addKeyword1("implements"); - table.addKeyword1("interface"); - table.addKeyword1("abstract"); - table.addKeyword1("char"); - table.addKeyword1("try"); - table.addKeyword1("catch"); - table.addKeyword1("finally"); - table.addKeyword1("synchronized"); - - return table; - } - - public void testParseSampleCode() { - String sampleCode = - "private some text f b g\n\n\n// 1\n public static void main(String[] args) {\n}\n-10 - 10\n\"dsfdfdf\"\n/* a\n *bc */"; - String sampleCode2 = "/*"; - String sampleCode3 = "//"; - String sampleCode4 = ""; - String sampleCode5 = " "; - - checkSameText(sampleCode); - String result; - - - IElementType[] types = new IElementType[]{CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.STRING, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.MULTI_LINE_COMMENT, - }; - - String[] matches = new String[]{"private", " ", "some", " ", "text", " ", "f", " ", "b", " ", "g", "\n\n\n", "// 1", "\n ", "public", - " ", "static", " ", "void", " ", "main", "(", - "String", "[", "]", " ", "args", ")", " ", "{", "\n", "}", "\n", "-", "10", - " ", "-", " ", "10", "\n", "\"dsfdfdf\"", "\n", "/* a\n *bc */", - }; - - checkTypesAndTokens(sampleCode, types, matches); - - lexer.start(sampleCode2); - assertEquals(CustomHighlighterTokenType.MULTI_LINE_COMMENT, lexer.getTokenType()); - assertEquals("/*", sampleCode2.substring(lexer.getTokenStart(), lexer.getTokenEnd())); - - lexer.start(sampleCode3); - assertEquals(CustomHighlighterTokenType.LINE_COMMENT, lexer.getTokenType()); - assertEquals("//", sampleCode3.substring(lexer.getTokenStart(), lexer.getTokenEnd())); - - lexer.start(sampleCode4); - assertEquals(null, lexer.getTokenType()); - assertEquals("", sampleCode4.substring(lexer.getTokenStart(), lexer.getTokenEnd())); - - lexer.start(sampleCode5); - assertEquals(CustomHighlighterTokenType.WHITESPACE, lexer.getTokenType()); - assertEquals(" ", sampleCode5.substring(lexer.getTokenStart(), lexer.getTokenEnd())); - } - - public void testParseSampleCodeFromTo() { - String sampleCode = " int n=123;\n float z=1;"; - lexer.start(sampleCode, 5, 5); - assertEquals(lexer.getTokenType(), null); - lexer.start(sampleCode, 5, 6); - lexer.getTokenType(); - assertEquals(5, lexer.getTokenStart()); - assertEquals(6, lexer.getTokenEnd()); - assertEquals(6, lexer.getBufferEnd()); - } -} diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/PropertiesFileTest.java b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/PropertiesFileTest.java deleted file mode 100644 index 88c956c403a8..000000000000 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/PropertiesFileTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.intellij.ide.highlighter.custom; - -import com.intellij.psi.CustomHighlighterTokenType; -import com.intellij.psi.tree.IElementType; - -/** - * @author dsl - */ -public class PropertiesFileTest extends CustomFileTypeLexerTestBase { - - @Override - protected void setUp() throws Exception { - lexer = new CustomFileTypeLexer(createSyntaxTable()); - } - - @Override - protected SyntaxTable createSyntaxTable() { - SyntaxTable table = new SyntaxTable(); - - table.setLineComment("#"); - table.setIgnoreCase(true); - - table.addKeyword1("value"); - table.addKeyword2("Value"); - table.setNumPostfixChars("LGH"); - return table; - } - - public void testSimple() { - String sampleFile = - "# Comment\n" + - "x.1.a=12.2L\n" + - " y.2.b=13.4 # comment\n" + - "VALUE value VaLuE Value1 17.00h 11.0k"; - checkSameText(sampleFile); - IElementType[] types = { - CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.WHITESPACE, - - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.PUNCTUATION, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.PUNCTUATION, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.WHITESPACE, - - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.PUNCTUATION, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.PUNCTUATION, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.WHITESPACE, - - CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.PUNCTUATION, - CustomHighlighterTokenType.NUMBER, - CustomHighlighterTokenType.IDENTIFIER - }; - - String[] matches = { - "# Comment", "\n", - - "x", ".", "1", ".", "a", "=", "12.2L", "\n ", - "y", ".", "2", ".", "b", "=", "13.4", " ", "# comment", "\n", - "VALUE", " ", "value", " ", "VaLuE", " ", "Value1", " ", "17.00h", " ", "11", ".", "0", "k" - }; - - checkTypesAndTokens(sampleFile, types, matches); - } - - public void testNumber() { - String sample = "1.23=1.24"; - checkSameText(sample); - IElementType[] types = { - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.NUMBER - }; - String[] matches = { "1.23", "=", "1.24" }; - checkTypesAndTokens(sample, types, matches); - } - - public void testPostfix() { - String sample = "abc 1.2ltext"; - checkSameText(sample); - IElementType[] types = { - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.IDENTIFIER - }; - String[] matches = { "abc", " ", "1.2l", "text" }; - checkTypesAndTokens(sample, types, matches); - } - - public void testWeird() { - String sample = "test.1."; - checkSameText(sample); - IElementType[] types = { - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.PUNCTUATION, CustomHighlighterTokenType.NUMBER - }; - String[] matches = { "test", ".", "1." }; - checkTypesAndTokens(sample, types, matches); - } - - public void testParenths() throws Exception { - String sample = "value(255)"; - checkSameText(sample); - IElementType[] types = { - CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.CHARACTER - }; - String[] matches = { "value", "(", "255", ")" }; - checkTypesAndTokens(sample, types, matches); - } -} diff --git a/platform/testFramework/src/com/intellij/testFramework/LexerTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LexerTestCase.java index a9e6435fcc9b..ed4f46179fba 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LexerTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LexerTestCase.java @@ -72,7 +72,7 @@ public abstract class LexerTestCase extends UsefulTestCase { return printTokens(text, start, createLexer()); } - private static String printTokens(String text, int start, Lexer lexer) { + public static String printTokens(String text, int start, Lexer lexer) { lexer.start(text, start, text.length()); String result = ""; while (true) { From d96aafc266a1d878ee6105893a37b491f766b8ed Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 10 Mar 2012 16:48:27 +0400 Subject: [PATCH 38/44] IDEA-82441 KeywordParser creates invalid RegExprs for custom languages --- .../custom/tokens/KeywordParser.java | 19 ++++++++++++++++--- .../custom/CustomFileTypeLexerTest.groovy | 17 +++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java index 2e243827fdc6..239a3501b392 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java @@ -47,19 +47,32 @@ public class KeywordParser extends TokenParser { if (regex.length() > 0) { regex.append("|"); } - regex.append(word); + regex.append(escapeSpecialCharacters(word)); } } Pattern pattern = null; try { - pattern = Pattern.compile("(" + regex + ")($|[\\W])", (ignoreCase ? Pattern.CASE_INSENSITIVE : 0) | Pattern.DOTALL); + String pat = "(" + regex + ")($|[^\\w-])"; + pattern = Pattern.compile(pat, (ignoreCase ? Pattern.CASE_INSENSITIVE : 0) | Pattern.DOTALL); } catch (PatternSyntaxException e) { - LOG.error(e); + LOG.info(e); } myPattern = pattern; } + private static String escapeSpecialCharacters(String word) { + StringBuilder esc = new StringBuilder(); + word = word.replace("\\", "\\\\"); + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if ("-*+?$%^.()".indexOf(ch) >= 0) esc.append('\\'); + esc.append(ch); + } + word = esc.toString(); + return word; + } + private Set getKeywordSet(Set keywordSet) { if (!myIgnoreCase) { return new THashSet(keywordSet); diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy index a709c66bed81..b7333a184b5a 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy @@ -300,5 +300,22 @@ CHARACTER (')') ''' } + public void testSpecialCharactersInKeywords() { + SyntaxTable table = new SyntaxTable() + table.addKeyword1("a*") + table.addKeyword1("b-c") + table.addKeyword2("d#") + table.addKeyword2("e") + doTest table, 'a* b-c d# e-', '''\ +KEYWORD_1 ('a*') +WHITESPACE (' ') +KEYWORD_1 ('b-c') +WHITESPACE (' ') +KEYWORD_2 ('d#') +WHITESPACE (' ') +IDENTIFIER ('e-') +''' + } + } From 9da59c659bbf97a6a1f818bdafd09f519c2770ff Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Sat, 10 Mar 2012 22:43:16 +0400 Subject: [PATCH 39/44] Parser --- .../componentTree/AndroidTreeDecorator.java | 15 +- .../AndroidDesignerEditorPanel.java | 138 ++------------ .../android/designer/icons/unknown.png | Bin 0 -> 842 bytes .../android/designer/model/ModelParser.java | 177 ++++++++++++++++++ .../designer/model/PropertyParser.java | 113 +++++++++++ .../designer/model/RadLinearLayout.java | 22 +++ .../designer/model/RadViewComponent.java | 129 ++----------- .../android/designer/model/RadViewLayout.java | 32 +--- .../designer/model/views-meta-model.xml | 19 +- .../intellij/designer/model/MetaManager.java | 8 +- 10 files changed, 370 insertions(+), 283 deletions(-) create mode 100644 plugins/android-designer/src/com/intellij/android/designer/icons/unknown.png create mode 100644 plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java create mode 100644 plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java create mode 100644 plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java diff --git a/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java b/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java index 7738eaab0d47..af65241836cb 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java +++ b/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java @@ -29,14 +29,11 @@ public final class AndroidTreeDecorator extends TreeComponentDecorator { public void decorate(RadComponent component, ColoredTreeCellRenderer renderer) { MetaModel metaModel = component.getMetaModel(); - // TODO - if (metaModel == null) { - RadViewComponent viewComponent = (RadViewComponent)component; - renderer.append(viewComponent.getTag().getName()); - } - else { - renderer.append(metaModel.getPaletteItem().getTitle()); - renderer.setIcon(metaModel.getIcon()); - } + StringBuffer fullTitle = new StringBuffer(); + String title1 = new String(metaModel.getPaletteItem().getTitle()); + fullTitle.append(title1.replaceAll("%tag%", ((RadViewComponent)component).getTag().getName())); + renderer.append(fullTitle.toString()); + + renderer.setIcon(metaModel.getIcon()); } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java index e02de1ae423f..fe9a90bb7f99 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java @@ -17,12 +17,13 @@ package com.intellij.android.designer.designSurface; import com.android.ide.common.rendering.api.RenderSession; import com.android.ide.common.rendering.api.Result; -import com.android.ide.common.rendering.api.ViewInfo; import com.android.ide.common.resources.configuration.*; +import com.android.sdklib.IAndroidTarget; import com.intellij.android.designer.actions.ProfileAction; import com.intellij.android.designer.componentTree.AndroidTreeDecorator; +import com.intellij.android.designer.model.ModelParser; +import com.intellij.android.designer.model.PropertyParser; import com.intellij.android.designer.model.RadViewComponent; -import com.intellij.android.designer.model.ViewsMetaManager; import com.intellij.android.designer.profile.ProfileManager; import com.intellij.designer.DesignerToolWindowManager; import com.intellij.designer.componentTree.TreeComponentDecorator; @@ -30,14 +31,10 @@ import com.intellij.designer.designSurface.ComponentDecorator; import com.intellij.designer.designSurface.DesignerEditorPanel; import com.intellij.designer.designSurface.EditOperation; import com.intellij.designer.designSurface.OperationContext; -import com.intellij.designer.designSurface.selection.DirectionResizePoint; -import com.intellij.designer.designSurface.selection.ResizeSelectionDecorator; +import com.intellij.designer.designSurface.selection.NonResizeSelectionDecorator; import com.intellij.designer.designSurface.tools.ComponentCreationFactory; import com.intellij.designer.designSurface.tools.ComponentPasteFactory; -import com.intellij.designer.model.MetaManager; -import com.intellij.designer.model.RadComponent; import com.intellij.designer.palette.Item; -import com.intellij.designer.utils.Position; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.util.Computable; @@ -45,16 +42,13 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; -import com.intellij.psi.XmlRecursiveElementVisitor; import com.intellij.psi.xml.XmlFile; -import com.intellij.psi.xml.XmlTag; import com.intellij.util.ThrowableRunnable; +import org.jetbrains.android.dom.attrs.AttributeDefinitions; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.sdk.AndroidPlatform; -import org.jetbrains.android.uipreview.LayoutDeviceConfiguration; -import org.jetbrains.android.uipreview.LocaleData; -import org.jetbrains.android.uipreview.RenderUtil; -import org.jetbrains.android.uipreview.RenderingException; +import org.jetbrains.android.sdk.AndroidTargetData; +import org.jetbrains.android.uipreview.*; import org.jetbrains.android.util.AndroidSdkNotConfiguredException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -62,7 +56,6 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.Collections; import java.util.List; /** @@ -132,52 +125,24 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { } } - private void parseFile(final Runnable runnable) { - final RadViewComponent[] rootComponents = new RadViewComponent[1]; - final MetaManager metaManager = ViewsMetaManager.getInstance(getProject()); - final String layoutXmlText = ApplicationManager.getApplication().runReadAction(new Computable() { - RadViewComponent myComponent; - - @Override - public String compute() { - XmlTag root = myXmlFile.getRootTag(); - if (root != null) { - root.accept(new XmlRecursiveElementVisitor() { - @Override - public void visitXmlTag(XmlTag tag) { - myComponent = new RadViewComponent(myComponent); - myComponent.setTag(tag); - myComponent.setMetaModel(metaManager.getModelByTag(tag.getName())); - - if (rootComponents[0] == null) { - rootComponents[0] = myComponent; - } - - super.visitXmlTag(tag); - - myComponent = (RadViewComponent)myComponent.getParent(); - } - }); - } - - return myXmlFile.getText(); - } - }); - - createRenderer(layoutXmlText, new ThrowableRunnable() { + private void parseFile(final Runnable runnable) throws Exception { + final ModelParser parser = new ModelParser(getProject(), myXmlFile); + createRenderer(parser.getLayoutXmlText(), new ThrowableRunnable() { @Override public void run() throws Throwable { checkRenderer(); RootView rootView = new RootView(mySession.getImage(), 30, 20); - updateRootComponent(rootComponents, mySession.getRootViews(), rootView); + parser.updateRootComponent(mySession.getRootViews(), rootView); + + new PropertyParser(myModule, myProfileAction.getProfileManager().getSelectedTarget()).loadRecursive(parser.getRootComponent()); JPanel rootPanel = new JPanel(null); rootPanel.setBackground(Color.WHITE); rootPanel.add(rootView); removeNativeRoot(); - myRootComponent = rootComponents[0]; + myRootComponent = parser.getRootComponent(); myLayeredPane.add(rootPanel, LAYER_COMPONENT); runnable.run(); @@ -200,7 +165,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { RadViewComponent rootComponent = (RadViewComponent)myRootComponent; RootView rootView = (RootView)rootComponent.getNativeComponent(); rootView.setImage(mySession.getImage()); - updateRootComponent(rootComponent, mySession.getRootViews(), rootView); + ModelParser.updateRootComponent(rootComponent, mySession.getRootViews(), rootView); myLayeredPane.repaint(); } @@ -210,6 +175,8 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { private void checkRenderer() throws Throwable { Result result = mySession.getResult(); if (!result.isSuccess()) { + System.out.println( + "No session: " + result.getErrorMessage() + " : " + result.getStatus() + " : " + result.getData() + " : " + result.getException()); Throwable exception = result.getException(); if (exception != null) { throw exception; @@ -226,55 +193,6 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { } } - private void updateRootComponent(RadViewComponent[] rootComponents, List views, JComponent nativeComponent) { - RadViewComponent rootComponent = rootComponents[0]; - - if (views.size() == 1) { - RadViewComponent newRootComponent = new RadViewComponent(null); - newRootComponent.setMetaModel(ViewsMetaManager.getInstance(getProject()).getModelByTag("")); - newRootComponent.getChildren().add(rootComponent); - rootComponent.setParent(newRootComponent); - - updateComponent(rootComponent, views.get(0), nativeComponent, 0, 0); - - rootComponents[0] = newRootComponent; - - newRootComponent.setNativeComponent(nativeComponent); - newRootComponent.setBounds(0, 0, nativeComponent.getWidth(), nativeComponent.getHeight()); - } - else { - updateRootComponent(rootComponent, views, nativeComponent); - } - } - - private static void updateRootComponent(RadViewComponent rootComponent, List views, JComponent nativeComponent) { - int size = views.size(); - List children = rootComponent.getChildren(); - for (int i = 0; i < size; i++) { - updateComponent((RadViewComponent)children.get(i), views.get(i), nativeComponent, 0, 0); - } - - rootComponent.setNativeComponent(nativeComponent); - rootComponent.setBounds(0, 0, nativeComponent.getWidth(), nativeComponent.getHeight()); - } - - private static void updateComponent(RadViewComponent component, ViewInfo view, JComponent nativeComponent, int parentX, int parentY) { - component.setNativeComponent(nativeComponent); - - int left = parentX + view.getLeft(); - int top = parentY + view.getTop(); - component.setBounds(left, top, view.getRight() - view.getLeft(), view.getBottom() - view.getTop()); - - List views = view.getChildren(); - List children = component.getChildren(); - int size = views.size(); - - for (int i = 0; i < size; i++) { - updateComponent((RadViewComponent)children.get(i), views.get(i), nativeComponent, left, top); - } - } - - private void createRenderer(final String layoutXmlText, final ThrowableRunnable runnable) { if (mySession == null) { ApplicationManager.getApplication().invokeLater( @@ -407,9 +325,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { @Override protected ComponentDecorator getRootSelectionDecorator() { - return new ResizeSelectionDecorator(Color.RED, 1, new DirectionResizePoint(Position.EAST, "top_resize_"), - new DirectionResizePoint(Position.SOUTH_EAST, "top_resize"), - new DirectionResizePoint(Position.SOUTH, "top_resize")); + return new NonResizeSelectionDecorator(Color.RED, 1); } @Override @@ -420,26 +336,12 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { @Override @NotNull protected ComponentCreationFactory createCreationFactory(Item paletteItem) { - return new ComponentCreationFactory() { - @Override - @NotNull - public RadComponent create() throws Exception { - return new RadViewComponent(null); - } - }; - //return null; // TODO: Auto-generated method stub + return null; // TODO: Auto-generated method stub } @Override public ComponentPasteFactory createPasteFactory(String xmlComponents) { - return new ComponentPasteFactory() { - @NotNull - @Override - public List create() throws Exception { - return Collections.singletonList(new RadViewComponent(null)); - } - }; - //return null; // TODO: Auto-generated method stub + return null; // TODO: Auto-generated method stub } @Override diff --git a/plugins/android-designer/src/com/intellij/android/designer/icons/unknown.png b/plugins/android-designer/src/com/intellij/android/designer/icons/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..f3556e07975888aef858d092ef3533e20c07749a GIT binary patch literal 842 zcmV-Q1GW5#P)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;z)3_wRCwBA{Qv(y10?_;fLIJ%64Ax@fY=j=j{)&x zsF*AeTLJO*3w!2&Le>KiKulN+O$Fk9AZ|nwYlMoWqALanAQmhJ>;Pg*sI3f0E;t62 zLjeE*gw24fKpXfe4_!PhaHTC9r;Fw*?3QK>)u01oj;8V)7*G z{xC#g%MBm>W;8q^S~wI=0rL3(0O|b3038YR038870Q~(30IAoqN!9z%s0Q2-b?+|b zgaY~l6#|Hf@i+60zwCebe)Ilt5i|=ksIMW%z{AGC@ZqBg1NSd21}75(hX235 zF=+9)F#Hz$ZVOWTi~qYc*K__C0096&0KWeN8yGeh@hIs+`4aX*0uK5T9|1lC%+A;V zi;|)M^Zot+6B!Nw%E{dTke8() { + @Override + public String compute() { + XmlTag root = myXmlFile.getRootTag(); + if (root != null) { + root.accept(ModelParser.this); + } + + return myXmlFile.getText(); + } + }); + } + + @Override + public void visitXmlTag(XmlTag tag) { + try { + MetaModel metaModel = myMetaManager.getModelByTag(tag.getName()); + if (metaModel == null) { + metaModel = myMetaManager.getModelByTag(""); + } + + RadViewComponent component = createComponent(tag, metaModel); + + if (myRootComponent == null) { + myRootComponent = component; + } + + component.setParent(myComponent); + if (myComponent != null) { + myComponent.getChildren().add(component); + } + + myComponent = component; + super.visitXmlTag(tag); + myComponent = (RadViewComponent)component.getParent(); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + private static RadViewComponent createComponent(XmlTag tag, MetaModel metaModel) throws Exception { + RadViewComponent component = (RadViewComponent)metaModel.getModel().newInstance(); + component.setMetaModel(metaModel); + component.setTag(tag); + + Class layout = metaModel.getLayout(); + if (layout != null) { + component.setLayout(layout.newInstance()); + } + + return component; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // + // + ////////////////////////////////////////////////////////////////////////////////////////// + + public RadViewComponent getRootComponent() { + return myRootComponent; + } + + public String getLayoutXmlText() { + return myLayoutXmlText; + } + + public void updateRootComponent(List views, JComponent nativeComponent) throws Exception { + RadViewComponent rootComponent = myRootComponent; + + if (views.size() == 1) { + RadViewComponent newRootComponent = createComponent(myXmlFile.getRootTag(), myMetaManager.getModelByTag("")); + rootComponent.setParent(newRootComponent); + newRootComponent.getChildren().add(rootComponent); + + updateComponent(rootComponent, views.get(0), nativeComponent, 0, 0); + + newRootComponent.setNativeComponent(nativeComponent); + newRootComponent.setBounds(0, 0, nativeComponent.getWidth(), nativeComponent.getHeight()); + + myRootComponent = newRootComponent; + } + else { + updateRootComponent(rootComponent, views, nativeComponent); + } + } + + public static void updateRootComponent(RadViewComponent rootComponent, + List views, + JComponent nativeComponent) { + int size = views.size(); + List children = rootComponent.getChildren(); + for (int i = 0; i < size; i++) { + updateComponent((RadViewComponent)children.get(i), views.get(i), nativeComponent, 0, 0); + } + + rootComponent.setNativeComponent(nativeComponent); + rootComponent.setBounds(0, 0, nativeComponent.getWidth(), nativeComponent.getHeight()); + } + + private static void updateComponent(RadViewComponent component, + ViewInfo view, + JComponent nativeComponent, + int parentX, + int parentY) { + component.setViewInfo(view); + component.setNativeComponent(nativeComponent); + + int left = parentX + view.getLeft(); + int top = parentY + view.getTop(); + component.setBounds(left, top, view.getRight() - view.getLeft(), view.getBottom() - view.getTop()); + + List views = view.getChildren(); + List children = component.getChildren(); + int size = views.size(); + + for (int i = 0; i < size; i++) { + updateComponent((RadViewComponent)children.get(i), views.get(i), nativeComponent, left, top); + } + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java new file mode 100644 index 000000000000..d89c38a908f0 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java @@ -0,0 +1,113 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.model; + +import com.android.ide.common.rendering.api.ViewInfo; +import com.android.sdklib.IAndroidTarget; +import com.intellij.designer.model.MetaManager; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.propertyTable.Property; +import com.intellij.openapi.module.Module; +import org.jetbrains.android.dom.attrs.AttributeDefinition; +import org.jetbrains.android.dom.attrs.AttributeDefinitions; +import org.jetbrains.android.dom.attrs.StyleableDefinition; +import org.jetbrains.android.sdk.AndroidPlatform; +import org.jetbrains.android.sdk.AndroidTargetData; +import org.jetbrains.android.uipreview.ProjectClassLoader; +import org.jetbrains.android.uipreview.RenderServiceFactory; + +import java.util.*; + +/** + * @author Alexander Lobas + */ +@SuppressWarnings("unchecked") +public class PropertyParser { + private AttributeDefinitions myDefinitions; + private ProjectClassLoader myClassLoader; + private Map> myCachedAttributes; + + public PropertyParser(Module module, IAndroidTarget target) throws Exception { + MetaManager metaManager = ViewsMetaManager.getInstance(module.getProject()); + myCachedAttributes = (Map>)metaManager.getCache().get(target.hashString()); + if (myCachedAttributes == null) { + myCachedAttributes = new HashMap>(); + metaManager.getCache().put(target.hashString(), myCachedAttributes); + } + + AndroidPlatform androidPlatform = AndroidPlatform.getInstance(module); + AndroidTargetData targetData = androidPlatform.getSdkData().getTargetData(target); + myDefinitions = targetData.getAttrDefs(module.getProject()); + + RenderServiceFactory factory = targetData.getRenderServiceFactory(module.getProject()); + myClassLoader = new ProjectClassLoader(factory.getLibrary().getClassLoader(), module); + } + + public void loadRecursive(RadViewComponent component) throws Exception { + load(component); + + for (RadComponent child : component.getChildren()) { + loadRecursive((RadViewComponent)child); + } + } + + public void load(RadViewComponent component) throws Exception { + List properties = new ArrayList(); + component.setProperties(properties); + + ViewInfo info = component.getViewInfo(); + if (info == null) { + return; + } + + List attributes = loadAttributes(myClassLoader.loadClass(info.getClassName())); + for (AttributeDefinition attribute : attributes) { + // TODO + } + } + + private List loadAttributes(Class componentClass) { + String component = componentClass.getSimpleName(); + List attributes = myCachedAttributes.get(component); + + if (attributes == null) { + attributes = new ArrayList(); + + StyleableDefinition attributeDefs = myDefinitions.getStyleableByName(component); + if (attributeDefs != null) { + attributes.addAll(attributeDefs.getAttributes()); + } + + Class superComponentClass = componentClass.getSuperclass(); + if (superComponentClass != null) { + attributes.addAll(loadAttributes(superComponentClass)); + } + + if (!attributes.isEmpty()) { + Collections.sort(attributes, new Comparator() { + @Override + public int compare(AttributeDefinition a1, AttributeDefinition a2) { + return a1.getName().compareTo(a2.getName()); + } + }); + } + + myCachedAttributes.put(component, attributes); + } + + return attributes; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java new file mode 100644 index 000000000000..1d9f893bfc41 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java @@ -0,0 +1,22 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.model; + +/** + * @author Alexander Lobas + */ +public class RadLinearLayout extends RadViewLayout { +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java index 5693abda2e5a..c5284df9f637 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java @@ -15,22 +15,10 @@ */ package com.intellij.android.designer.model; +import com.android.ide.common.rendering.api.ViewInfo; import com.intellij.designer.model.RadComponent; import com.intellij.designer.propertyTable.Property; -import com.intellij.designer.propertyTable.PropertyEditor; -import com.intellij.designer.propertyTable.PropertyRenderer; -import com.intellij.designer.propertyTable.editors.BooleanEditor; -import com.intellij.designer.propertyTable.renderers.BooleanRenderer; -import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.util.IconLoader; -import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -38,32 +26,16 @@ import java.util.ArrayList; import java.util.List; /** - * TODO: now dummy implementation for tests - * * @author Alexander Lobas */ public class RadViewComponent extends RadComponent { - public static final AnAction LinearLayout = - new AnAction("Horizontal/Vertical", "LinearLayout", IconLoader.getIcon("/com/intellij/android/designer/icons/LinearLayout.png")) { - @Override - public void actionPerformed(AnActionEvent e) { - } - }; - private final List myChildren = new ArrayList(); + private ViewInfo myViewInfo; private Component myNativeComponent; private final Rectangle myBounds = new Rectangle(); private XmlTag myTag; private List myProperties; - public RadViewComponent(RadViewComponent parent) { - setParent(parent); - if (parent != null) { - parent.getChildren().add(this); - } - setLayout(new RadViewLayout(this)); - } - public XmlTag getTag() { return myTag; } @@ -77,6 +49,14 @@ public class RadViewComponent extends RadComponent { return myChildren; } + public ViewInfo getViewInfo() { + return myViewInfo; + } + + public void setViewInfo(ViewInfo viewInfo) { + myViewInfo = viewInfo; + } + @Override public Rectangle getBounds() { return myBounds; @@ -105,92 +85,11 @@ public class RadViewComponent extends RadComponent { } @Override - public void addSelectionActions(DefaultActionGroup actionGroup, JComponent shortcuts, List selection) { - if (myTag != null && myTag.getName().equals("LinearLayout") && selection.size() == 1 && selection.get(0) == this) { - AnAction action = new AnAction() { - @Override - public void actionPerformed(AnActionEvent e) { - System.out.println("LinearLayout: " + e); - } - }; - action.copyFrom(LinearLayout); - actionGroup.add(action); - } + public List getProperties() { + return myProperties; } - @Override - public List getProperties() { - if (myProperties == null && myTag != null) { - myProperties = new ArrayList(); - Property layout = new Property(null, "layout") { - private final BooleanRenderer myRenderer = new BooleanRenderer(); - private final BooleanEditor myEditor = new BooleanEditor(); - private final List myProperties = new ArrayList(); - - @Override - public List getChildren(@Nullable RadComponent component) { - return myProperties; - } - - @Override - public Object getValue(RadComponent component) throws Exception { - return component.getClientProperty(getName()); - } - - @Override - public void setValue(RadComponent component, Object value) throws Exception { - component.putClientProperty(getName(), value); - } - - @Override - public boolean isDefaultValue(RadComponent component) throws Exception { - return getValue(component) == null; - } - - @Override - public void setDefaultValue(RadComponent component) throws Exception { - component.putClientProperty(getName(), null); - } - - @NotNull - @Override - public PropertyRenderer getRenderer() { - return myRenderer; - } - - @Override - public PropertyEditor getEditor() { - return myEditor; - } - }; - layout.setImportant(true); - - for (XmlAttribute attribute : myTag.getAttributes()) { - String name = attribute.getName(); - if (name.equals("xmlns:android")) { - continue; - } - - Property parent = name.equals("android:layout_width") || name.equals("android:layout_height") ? layout : null; - Property property = new AttributeProperty(parent, new String(name).replace("android:", "").replace('_', ' '), name); - property.setImportant(name.equals("android:text")); - property.setExpert(name.equals("android:id")); - if (name.equals("android:background")) { - property.setDeprecated(true); - property.setImportant(true); - } - if (parent == null) { - myProperties.add(property); - } - else { - layout.getChildren(null).add(property); - } - } - - if (!layout.getChildren(null).isEmpty()) { - myProperties.add(0, layout); - } - } - return myProperties == null ? super.getProperties() : myProperties; + public void setProperties(List properties) { + myProperties = properties; } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java index c9872c80f061..97ff2f279b70 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java @@ -17,14 +17,9 @@ package com.intellij.android.designer.model; import com.intellij.designer.designSurface.ComponentDecorator; import com.intellij.designer.designSurface.selection.NonResizeSelectionDecorator; -import com.intellij.designer.model.MetaModel; import com.intellij.designer.model.RadComponent; import com.intellij.designer.model.RadLayout; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import javax.swing.*; import java.awt.*; import java.util.List; @@ -32,33 +27,8 @@ import java.util.List; * @author Alexander Lobas */ public class RadViewLayout extends RadLayout { - private final RadViewComponent myContainer; - - public RadViewLayout(RadViewComponent container) { - myContainer = container; - } - - @Override + @Override public ComponentDecorator getChildSelectionDecorator(RadComponent component, List selection) { return new NonResizeSelectionDecorator(Color.RED, 1); } - - @Override - public void addSelectionActions(DefaultActionGroup actionGroup, JComponent shortcuts, List selection) { - if (myContainer.getTag() != null && myContainer.getTag().getName().equals("LinearLayout")) { - for (RadComponent component : selection) { - if (myContainer != component.getParent()) { - return; - } - } - AnAction action = new AnAction() { - @Override - public void actionPerformed(AnActionEvent e) { - System.out.println("LinearLayout: " + e); - } - }; - action.copyFrom(RadViewComponent.LinearLayout); - actionGroup.add(action); - } - } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml index 449fc164cf2c..3c22363a76ce 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml +++ b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml @@ -1,17 +1,26 @@ + + + + + @@ -51,7 +60,7 @@ @@ -70,14 +79,6 @@ - - - - - - - - \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java index 22d11dae714c..fdc64b146f98 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java @@ -21,7 +21,6 @@ import com.intellij.ide.palette.PaletteGroup; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.util.containers.hash.HashMap; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; @@ -30,6 +29,7 @@ import org.jetbrains.annotations.Nullable; import java.beans.PropertyChangeSupport; import java.io.InputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -52,6 +52,8 @@ public abstract class MetaManager { private PropertyChangeSupport myPaletteChangeSupport; + private Map myCache = new HashMap(); + protected MetaManager(Project project, String name) { try { InputStream stream = getClass().getResourceAsStream(name); @@ -119,6 +121,10 @@ public abstract class MetaManager { myPaletteGroups.add(group); } + public Map getCache() { + return myCache; + } + @Nullable public MetaModel getModelByTag(String tag) { return myTag2Model.get(tag); From efd7e800e76d8c4a4ea5388294b0697f949e086c Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Tue, 6 Mar 2012 14:31:31 +0400 Subject: [PATCH 40/44] IDEA-76142: Gradle support - cannot update IDEA projects once one of build.gradle files changes Cleanup --- ...leAbstractDependencyStructureChangesCalculator.java | 1 - .../GradleContentRootStructureChangesCalculator.java | 1 - .../diff/GradleModuleStructureChangesCalculator.java | 1 - .../plugins/gradle/remote/GradleApiFacadeManager.java | 2 +- .../gradle/sync/GradleProjectStructureTreeModel.java | 4 ---- .../org/jetbrains/plugins/gradle/util/GradleUtil.java | 10 ++++++++-- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java index e982b0022e79..d4814b6a4b9f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java @@ -16,7 +16,6 @@ public abstract class GradleAbstractDependencyStructureChangesCalculator gradleContentRoots = gradleEntity.getContentRoots(); final Collection intellijContentRoots = context.getPlatformFacade().getContentRoots(intellijEntity); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java index b8488781f219..3f884ccec8b2 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java @@ -171,7 +171,7 @@ public class GradleApiFacadeManager { final GeneralCommandLine commandLine = JdkUtil.setupJVMCommandLine( ((JavaSdkType)sdk.getSdkType()).getVMExecutablePath(sdk), params, - false // TODO den check + false ); final OSProcessHandler processHandler = new OSProcessHandler(commandLine.createProcess(), commandLine.getCommandLineString()) { @Override diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java index 3f74a6e2adb7..1bb6991fb5ae 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java @@ -241,11 +241,9 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } private void processNewProjectRenameChange(@NotNull GradleProjectRenameChange change) { - // TODO den implement } private void processNewLanguageLevelChange(@NotNull GradleLanguageLevelChange change) { - // TODO den implement } private void processNewMismatchedLibraryPathChange(@NotNull GradleMismatchedLibraryPathChange change) { @@ -325,11 +323,9 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } private void processObsoleteProjectRenameChange(@NotNull GradleProjectRenameChange change) { - // TODO den implement } private void processObsoleteLanguageLevelChange(@NotNull GradleLanguageLevelChange change) { - // TODO den implement } private void processObsoleteMismatchedLibraryPathChange(@NotNull GradleMismatchedLibraryPathChange change) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java index 902e8027ad48..505bff71191b 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java @@ -256,8 +256,14 @@ public class GradleUtil { } return file.getPath(); } - - // TODO den add doc about relative coordinates + + /** + * Allows to calculate the position to use for showing hint for the given node of the given tree. + * + * @param node target node for which a hint should be shown + * @param tree target tree that contains given node + * @return preferred hint position (in coordinates relative to the given tree) + */ @NotNull public static Point getHintPosition(@NotNull GradleProjectStructureNode node, @NotNull Tree tree) { final Rectangle bounds = tree.getPathBounds(new TreePath(node.getPath())); From ac5b3b51bcf6cd8227a907e3d269eedd52883000 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Wed, 7 Mar 2012 19:40:25 +0400 Subject: [PATCH 41/44] IDEA-76142: Gradle support - cannot update IDEA projects once one of build.gradle files changes Added 'filters' toolbar --- .../resources/i18n/GradleBundle.properties | 1 + plugins/gradle/src/META-INF/plugin.xml | 16 ++++++- .../GradleAbstractSyncTreeFilterAction.java | 40 ++++++++++++++++ .../GradleConfirmedSyncTreeFilterAction.java | 14 ++++++ .../GradleConflictSyncTreeFilterAction.java | 14 ++++++ .../GradleLocalSyncTreeFilterAction.java | 14 ++++++ .../IntellijLocalSyncTreeFilterAction.java | 16 +++++++ ...GradleColorAndFontDescriptorsProvider.java | 48 ++++++++++--------- .../gradle/config/GradleToolWindowPanel.java | 34 +++++++++++-- .../GradleProjectStructureChangesPanel.java | 19 +++++--- .../GradleProjectStructureFiltersPanel.java | 27 +++++++++++ .../plugins/gradle/util/GradleConstants.java | 1 + 12 files changed, 210 insertions(+), 34 deletions(-) create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleAbstractSyncTreeFilterAction.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConfirmedSyncTreeFilterAction.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConflictSyncTreeFilterAction.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLocalSyncTreeFilterAction.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/action/IntellijLocalSyncTreeFilterAction.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureFiltersPanel.java diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties index ac778fa9870e..2fb6c89c3dcf 100644 --- a/plugins/gradle/resources/i18n/GradleBundle.properties +++ b/plugins/gradle/resources/i18n/GradleBundle.properties @@ -29,6 +29,7 @@ gradle.import.structure.settings.label.root.excluded=Excluded roots: gradle.import.structure.settings.label.library.path.binary=Binary paths gradle.import.structure.settings.label.library.path.source=Source paths gradle.import.structure.settings.label.library.path.doc=Doc paths +gradle.import.structure.settings.label.filters=Filters: gradle.import.title.error.resolve.generic=Resolve error gradle.import.text.error.resolve.generic.without.reason=Can''t resolve target gradle project at ''{0}'' diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index 72ac5c04f4c6..e3632268e9b6 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -100,16 +100,28 @@ - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleAbstractSyncTreeFilterAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleAbstractSyncTreeFilterAction.java new file mode 100644 index 000000000000..d819627d55c0 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleAbstractSyncTreeFilterAction.java @@ -0,0 +1,40 @@ +package org.jetbrains.plugins.gradle.action; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.options.colors.AttributesDescriptor; +import com.intellij.util.ui.ColorIcon; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Denis Zhdanov + * @since 3/7/12 3:48 PM + */ +public abstract class GradleAbstractSyncTreeFilterAction extends ToggleAction { + + @NotNull private final AttributesDescriptor myDescriptor; + + protected GradleAbstractSyncTreeFilterAction(@NotNull AttributesDescriptor descriptor) { + myDescriptor = descriptor; + getTemplatePresentation().setText(descriptor.getDisplayName()); + final Color color = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(descriptor.getKey()).getForegroundColor(); + getTemplatePresentation().setIcon(new ColorIcon(new JLabel("").getFont().getSize(), color)); + } + + @Override + public boolean isSelected(AnActionEvent e) { + // TODO den implement + return false; + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + // TODO den implement + System.out.println("GradleAbstractSyncTreeFilterAction.setSelected(): " + state); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConfirmedSyncTreeFilterAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConfirmedSyncTreeFilterAction.java new file mode 100644 index 000000000000..de21d9c421f8 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConfirmedSyncTreeFilterAction.java @@ -0,0 +1,14 @@ +package org.jetbrains.plugins.gradle.action; + +import org.jetbrains.plugins.gradle.config.GradleColorAndFontDescriptorsProvider; + +/** + * @author Denis Zhdanov + * @since 3/7/12 6:07 PM + */ +public class GradleConfirmedSyncTreeFilterAction extends GradleAbstractSyncTreeFilterAction { + + public GradleConfirmedSyncTreeFilterAction() { + super(GradleColorAndFontDescriptorsProvider.CONFIRMED); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConflictSyncTreeFilterAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConflictSyncTreeFilterAction.java new file mode 100644 index 000000000000..3ef8e0957b20 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConflictSyncTreeFilterAction.java @@ -0,0 +1,14 @@ +package org.jetbrains.plugins.gradle.action; + +import org.jetbrains.plugins.gradle.config.GradleColorAndFontDescriptorsProvider; + +/** + * @author Denis Zhdanov + * @since 3/7/12 6:08 PM + */ +public class GradleConflictSyncTreeFilterAction extends GradleAbstractSyncTreeFilterAction { + + public GradleConflictSyncTreeFilterAction() { + super(GradleColorAndFontDescriptorsProvider.CONFLICT); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLocalSyncTreeFilterAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLocalSyncTreeFilterAction.java new file mode 100644 index 000000000000..f0a59e30c5f4 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLocalSyncTreeFilterAction.java @@ -0,0 +1,14 @@ +package org.jetbrains.plugins.gradle.action; + +import org.jetbrains.plugins.gradle.config.GradleColorAndFontDescriptorsProvider; + +/** + * @author Denis Zhdanov + * @since 3/7/12 3:54 PM + */ +public class GradleLocalSyncTreeFilterAction extends GradleAbstractSyncTreeFilterAction { + + public GradleLocalSyncTreeFilterAction() { + super(GradleColorAndFontDescriptorsProvider.GRADLE_LOCAL); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/IntellijLocalSyncTreeFilterAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/IntellijLocalSyncTreeFilterAction.java new file mode 100644 index 000000000000..46bc43a9d51b --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/IntellijLocalSyncTreeFilterAction.java @@ -0,0 +1,16 @@ +package org.jetbrains.plugins.gradle.action; + +import com.intellij.openapi.options.colors.AttributesDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.config.GradleColorAndFontDescriptorsProvider; + +/** + * @author Denis Zhdanov + * @since 3/7/12 3:59 PM + */ +public class IntellijLocalSyncTreeFilterAction extends GradleAbstractSyncTreeFilterAction { + + public IntellijLocalSyncTreeFilterAction() { + super(GradleColorAndFontDescriptorsProvider.INTELLIJ_LOCAL); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleColorAndFontDescriptorsProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleColorAndFontDescriptorsProvider.java index 458659bac40b..d44ec89eb7f5 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleColorAndFontDescriptorsProvider.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleColorAndFontDescriptorsProvider.java @@ -17,28 +17,32 @@ import org.jetbrains.plugins.gradle.util.GradleBundle; */ public class GradleColorAndFontDescriptorsProvider implements ColorAndFontDescriptorsProvider { - private static final AttributesDescriptor[] DESCRIPTORS = { - new AttributesDescriptor( - GradleBundle.message("gradle.sync.change.type.conflict"), - GradleTextAttributes.CHANGE_CONFLICT - ), - new AttributesDescriptor( - GradleBundle.message("gradle.sync.change.type.confirmed"), - GradleTextAttributes.CONFIRMED_CONFLICT - ), - new AttributesDescriptor( - GradleBundle.message("gradle.sync.change.type.gradle"), - GradleTextAttributes.GRADLE_LOCAL_CHANGE - ), - new AttributesDescriptor( - GradleBundle.message("gradle.sync.change.type.intellij", ApplicationNamesInfo.getInstance().getProductName()), - GradleTextAttributes.INTELLIJ_LOCAL_CHANGE - ), - new AttributesDescriptor( - GradleBundle.message("gradle.sync.change.type.unchanged"), - GradleTextAttributes.NO_CHANGE - ) - }; + public static final AttributesDescriptor CONFLICT = new AttributesDescriptor( + GradleBundle.message("gradle.sync.change.type.conflict"), + GradleTextAttributes.CHANGE_CONFLICT + ); + + public static final AttributesDescriptor CONFIRMED = new AttributesDescriptor( + GradleBundle.message("gradle.sync.change.type.confirmed"), + GradleTextAttributes.CONFIRMED_CONFLICT + ); + + public static final AttributesDescriptor GRADLE_LOCAL = new AttributesDescriptor( + GradleBundle.message("gradle.sync.change.type.gradle"), + GradleTextAttributes.GRADLE_LOCAL_CHANGE + ); + + public static final AttributesDescriptor INTELLIJ_LOCAL = new AttributesDescriptor( + GradleBundle.message("gradle.sync.change.type.intellij", ApplicationNamesInfo.getInstance().getProductName()), + GradleTextAttributes.INTELLIJ_LOCAL_CHANGE + ); + + public static final AttributesDescriptor NO_CHANGE = new AttributesDescriptor( + GradleBundle.message("gradle.sync.change.type.unchanged", ApplicationNamesInfo.getInstance().getProductName()), + GradleTextAttributes.NO_CHANGE + ); + + private static final AttributesDescriptor[] DESCRIPTORS = { CONFLICT, CONFIRMED, GRADLE_LOCAL, INTELLIJ_LOCAL, NO_CHANGE }; @NotNull @Override diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java index 146fa370e035..316376fb5647 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java @@ -5,7 +5,9 @@ import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; +import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.SideBorder; import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,6 +16,8 @@ import org.jetbrains.plugins.gradle.util.GradleBundle; import javax.swing.*; import java.awt.*; +import java.util.Collections; +import java.util.List; /** * Base class for high-level Gradle GUI controls used at the Gradle tool window. The basic idea is to encapsulate the same features in @@ -42,14 +46,12 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { private final JPanel myContent = new JPanel(myLayout); private final Project myProject; + private final String myPlace; protected GradleToolWindowPanel(@NotNull Project project, @NotNull String place) { super(true); myProject = project; - final ActionManager actionManager = ActionManager.getInstance(); - final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(TOOL_WINDOW_TOOLBAR_ID); - ActionToolbar actionToolbar = actionManager.createActionToolbar(place, actionGroup, true); - setToolbar(actionToolbar.getComponent()); + myPlace = place; setContent(myContent); MessageBusConnection connection = project.getMessageBus().connect(project); @@ -62,6 +64,22 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { } public void initContent() { + final ActionManager actionManager = ActionManager.getInstance(); + final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(TOOL_WINDOW_TOOLBAR_ID); + ActionToolbar actionToolbar = actionManager.createActionToolbar(myPlace, actionGroup, true); + JPanel toolbarControl = new JPanel(new GridBagLayout()); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1; + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.anchor = GridBagConstraints.WEST; + toolbarControl.add(actionToolbar.getComponent(), constraints); + for (JComponent component : getToolbarControls()) { + component.setBorder(IdeBorderFactory.createBorder(SideBorder.TOP)); + toolbarControl.add(component, constraints); + } + setToolbar(toolbarControl); + final JComponent payloadControl = buildContent(); myContent.add(ScrollPaneFactory.createScrollPane(payloadControl), CONTENT_CARD_NAME); RichTextControlBuilder builder = new RichTextControlBuilder(); @@ -74,6 +92,14 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { update(); } + /** + * @return list of UI controls to be displayed vertically at the toolbar + */ + @NotNull + protected List getToolbarControls() { + return Collections.emptyList(); + } + /** * Asks current control to update its state. */ diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java index 994c9fb6f50d..3d72ad01668b 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java @@ -30,7 +30,6 @@ import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import java.awt.*; -import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.ArrayList; @@ -46,9 +45,10 @@ import java.util.List; public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { private static final int TOOLTIP_DELAY_MILLIS = 500; - - private final Alarm myToolbarAppearanceAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); - private final Alarm myToolbarTrackingAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + + private final Alarm myToolbarAppearanceAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + private final Alarm myToolbarTrackingAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + private final List myToolbarControls = new ArrayList(); private Tree myTree; private GradleProjectStructureTreeModel myTreeModel; @@ -75,6 +75,7 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { }); } }); + myToolbarControls.add(new GradleProjectStructureFiltersPanel()); initContent(); } @@ -93,6 +94,8 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { applyInitialAppearance(myTree, (DefaultMutableTreeNode)myTreeModel.getRoot()); GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.anchor = GridBagConstraints.WEST; constraints.fill = GridBagConstraints.BOTH; constraints.weightx = constraints.weighty = 1; result.add(myTree, constraints); @@ -103,10 +106,14 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { return result; } + @NotNull + @Override + protected List getToolbarControls() { + return myToolbarControls; + } + @Override protected void updateContent() { - // TODO den implement - int i = 1; } private void setupToolbar() { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureFiltersPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureFiltersPanel.java new file mode 100644 index 000000000000..9cdf3ba83ca9 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureFiltersPanel.java @@ -0,0 +1,27 @@ +package org.jetbrains.plugins.gradle.sync; + +import com.intellij.openapi.actionSystem.ActionGroup; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.ActionToolbar; +import org.jetbrains.plugins.gradle.util.GradleBundle; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import javax.swing.*; + +/** + * @author Denis Zhdanov + * @since 3/6/12 3:44 PM + */ +public class GradleProjectStructureFiltersPanel extends JPanel { + + + public GradleProjectStructureFiltersPanel() { + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + add(Box.createHorizontalStrut(7)); + add(new JLabel(GradleBundle.message("gradle.import.structure.settings.label.filters"))); + final ActionManager actionManager = ActionManager.getInstance(); + final ActionGroup group = (ActionGroup)actionManager.getAction("Gradle.SyncTreeFilter"); + final ActionToolbar toolbar = actionManager.createActionToolbar(GradleConstants.SYNC_TREE_FILTER_PLACE, group, true); + add(toolbar.getComponent()); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java index 5b24a6aed7ee..348a4c857903 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java @@ -18,6 +18,7 @@ public class GradleConstants { @NonNls public static final String TOOL_WINDOW_TOOLBAR_PLACE = "GRADLE_SYNC_CHANGES_TOOLBAR"; @NonNls public static final String SYNC_TREE_CONTEXT_MENU_PLACE = "GRADLE_SYNC_TREE_CONTEXT_MENU_PLACE"; @NonNls public static final String SYNC_TREE_FLOATING_TOOLBAR_PLACE = "GRADLE_SYNC_TREE_FLOATING_TOOLBAR_PLACE"; + @NonNls public static final String SYNC_TREE_FILTER_PLACE = "GRADLE_SYNC_TREE_FILTER_PLACE"; @NonNls public static final String ACTION_GROUP_SYNC_TREE = "Gradle.SyncTreeGroup"; From 5ecf149f796d009da49406614796afaa11367533 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Sun, 11 Mar 2012 11:12:12 +0400 Subject: [PATCH 42/44] IDEA-82529 Gradle: Fix 'window with id="Gradle" is already registered' Intellij plugin uses tool window 'JetGradle' now --- plugins/gradle/src/META-INF/plugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index e3632268e9b6..e0c9e44feedc 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -65,7 +65,7 @@ - From 1e8578698ba66669c0bbb7e60379dd071c38466b Mon Sep 17 00:00:00 2001 From: nik Date: Sun, 11 Mar 2012 11:21:35 +0400 Subject: [PATCH 43/44] test fixed --- .../artifacts/ArtifactBuilderTestCase.java | 25 ++++++++++++++++--- jps/model/src/org/jetbrains/jps/Module.groovy | 4 +-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java index c2f9e5bfffb2..89db4e5f1132 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java @@ -22,9 +22,7 @@ import com.intellij.util.io.TestFileSystemBuilder; import com.intellij.util.text.UniqueNameGenerator; import groovy.lang.Closure; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.Library; -import org.jetbrains.jps.Module; -import org.jetbrains.jps.Project; +import org.jetbrains.jps.*; import org.jetbrains.jps.api.CanceledStatus; import org.jetbrains.jps.artifacts.Artifact; import org.jetbrains.jps.incremental.*; @@ -32,6 +30,7 @@ import org.jetbrains.jps.incremental.java.JavaBuilderLoggerImpl; import org.jetbrains.jps.incremental.messages.BuildMessage; import org.jetbrains.jps.incremental.storage.BuildDataManager; import org.jetbrains.jps.incremental.storage.ProjectTimestamps; +import org.jetbrains.jps.server.ClasspathBootstrap; import org.jetbrains.jps.server.ProjectDescriptor; import java.io.File; @@ -48,6 +47,7 @@ public abstract class ArtifactBuilderTestCase extends UsefulTestCase { private Project myProject; private File myProjectDir; private TestArtifactBuilderLogger myArtifactBuilderLogger; + private Sdk myJdk; protected void setUp() throws Exception { super.setUp(); @@ -112,8 +112,21 @@ public abstract class ArtifactBuilderTestCase extends UsefulTestCase { } protected Module addModule(String moduleName, @Nullable String srcPath) { + if (myJdk == null) { + try { + myJdk = myProject.createSdk("JavaSDK", "jdk", System.getProperty("java.home"), null); + final List paths = new LinkedList(); + paths.add(FileUtil.toSystemIndependentName(ClasspathBootstrap.getResourcePath(Object.class).getCanonicalPath())); + myJdk.setClasspath(paths); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } final Module module = myProject.createModule(moduleName, Closure.IDENTITY); module.forceInit(); + module.setSdk(myJdk); + module.getDependencies().add(new Module.ModuleDependency(myJdk, PredefinedDependencyScopes.getCOMPILE(), false)); if (srcPath != null) { module.getContentRoots().add(srcPath); module.getSourceRoots().add(srcPath); @@ -163,12 +176,16 @@ public abstract class ArtifactBuilderTestCase extends UsefulTestCase { myArtifactBuilderLogger.clear(); IncProjectBuilder builder = new IncProjectBuilder(myDescriptor, BuilderRegistry.getInstance(), Collections.emptyMap(), CanceledStatus.NULL); final List errorMessages = new ArrayList(); + final List infoMessages = new ArrayList(); builder.addMessageHandler(new MessageHandler() { @Override public void processMessage(BuildMessage msg) { if (msg.getKind() == BuildMessage.Kind.ERROR) { errorMessages.add(msg); } + else { + infoMessages.add(msg); + } } }); builder.build(new AllProjectScope(myDescriptor.project, new HashSet(Arrays.asList(artifacts)), force), !force, false); @@ -176,7 +193,7 @@ public abstract class ArtifactBuilderTestCase extends UsefulTestCase { assertFalse("Build not failed as expected", errorMessages.isEmpty()); } else { - assertTrue("Build failed: " + errorMessages, errorMessages.isEmpty()); + assertTrue("Build failed. \nErrors:\n" + errorMessages + "\nInfo messages:\n" + infoMessages, errorMessages.isEmpty()); } } diff --git a/jps/model/src/org/jetbrains/jps/Module.groovy b/jps/model/src/org/jetbrains/jps/Module.groovy index 43323675d01c..7a3dd178408f 100644 --- a/jps/model/src/org/jetbrains/jps/Module.groovy +++ b/jps/model/src/org/jetbrains/jps/Module.groovy @@ -11,7 +11,7 @@ class Module extends LazyInitializeableObject implements ClasspathItem {//}, Com String name; Sdk sdk; - private List dependencies = [] + List dependencies = [] List contentRoots = [] List sourceRoots = [] List testRoots = [] @@ -115,7 +115,7 @@ class Module extends LazyInitializeableObject implements ClasspathItem {//}, Com return dependencies.findAll({it.scope.isIncludedIn(kind) && (!exportedOnly || it.exported)})*.item; } - private static class ModuleDependency { + public static class ModuleDependency { ClasspathItem item DependencyScope scope boolean exported From d5f2eca5f52bf49a1a0aeccb2d1abcb8126ccdad Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Sun, 11 Mar 2012 11:42:18 +0400 Subject: [PATCH 44/44] IDEA-82398 Reformat code broken for a string going past right margin 1. Don't wrap string which length is equal to the right margin; 2. Corresponding test is added; --- .../psi/formatter/java/JavaFormatterWrapTest.java | 14 +++++++++++++- .../impl/source/codeStyle/CodeFormatterFacade.java | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java index 6ecf24925f1a..070f2626f449 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -152,6 +152,18 @@ public class JavaFormatterWrapTest extends AbstractJavaFormatterTest { doClassTest(text, text); } + public void testWrapCompoundStringLiteralThatEndsAtRightMargin() { + // Inspired by IDEA-82398 + getSettings().getRootSettings().RIGHT_MARGIN = 30; + getSettings().getRootSettings().getCommonSettings(JavaLanguage.INSTANCE).WRAP_LONG_LINES = true; + + final String text = "class Test {\n" + + " String s = \"first line \" +\n" + + " +\"second line\";\n" + + "}"; + doTextTest(text, text); + } + public void testWrapLongLine() { // Inspired by IDEA-55782 getSettings().getRootSettings().RIGHT_MARGIN = 50; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java index 6db1c4aa405b..d9af7a4b628a 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -339,7 +339,7 @@ public class CodeFormatterFacade { int preferredWrapPosition = Integer.MAX_VALUE; if (!hasTabs) { - if (Math.min(endLineOffset, endOffsetToUse) - startLineOffset >= mySettings.RIGHT_MARGIN) { + if (Math.min(endLineOffset, endOffsetToUse) - startLineOffset > mySettings.RIGHT_MARGIN) { preferredWrapPosition = startLineOffset + mySettings.RIGHT_MARGIN - FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS; } }