Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ilya.Kazakevich
2015-04-16 20:43:10 +03:00
98 changed files with 2472 additions and 1361 deletions
+1
View File
@@ -5,3 +5,4 @@ IDC_WINLAUNCHER=__IDE-NAME___LAUNCHER
IDS_PROPS_ENV_VAR=__IDE-NAME___PROPERTIES
IDS_VM_OPTIONS_ENV_VAR=__IDE-NAME___VM_OPTIONS
IDS_ERROR_LAUNCHING_APP=Error launching __IDE-NAME__
IDS_VM_OPTIONS=-Didea.paths.selector=__PRODUCT_PATHS_SELECTOR__
+1
View File
@@ -6,3 +6,4 @@ IDC_WINLAUNCHER=__IDE-NAME___LAUNCHER
IDS_PROPS_ENV_VAR=__IDE-NAME___PROPERTIES
IDS_VM_OPTIONS_ENV_VAR=__IDE-NAME__64_VM_OPTIONS
IDS_ERROR_LAUNCHING_APP=Error launching __IDE-NAME__
IDS_VM_OPTIONS=-Didea.paths.selector=__PRODUCT_PATHS_SELECTOR__
+5
View File
@@ -15,6 +15,7 @@
*/
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.jps.gant.LayoutInfo
import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome
@@ -127,6 +128,10 @@ def layoutAll(Map args, String home, String out, Paths _paths = null, buildJps =
def layouts = includeFile("$home/build/scripts/layouts.gant")
LayoutInfo info = layouts.layoutFull(home, paths.distAll, null)
layouts.layout_core(home, paths.artifacts_core)
ant.zip(destfile: "${paths.artifacts}/intellij-core-${StringUtil.trimStart(args.buildNumber, "IC-")}.zip") {
fileset(dir: paths.artifacts_core)
}
notifyArtifactBuilt(paths.artifacts_core)
if (buildJps) {
layouts.layoutJps(home, paths.artifacts_jps, args.buildNumber, {})
+1
View File
@@ -25,6 +25,7 @@ def nsis_installer(pathsToInclude, stringsFile, pathsFile, outNamePrefix, includ
ant.mkdir(dir: "$box/jre")
requireProperty("jdk_bundled_win", "1.7")
def jdk_bundled_version = p("jdk_bundled_win") == "1.8" ? "${home}/build/jdk/jdk8_redist.zip" : "${home}/build/jdk/jdk_redist.zip"
getBundledJDK(new File("${home}/build/jdk/win"), "jdk"+ p("jdk_bundled_win"), "x32.zip", jdk_bundled_version)
ant.unzip(dest: "$box/jre", src: "${jdk_bundled_version}")
ant.copy(todir: "$box/bin") {
+11 -10
View File
@@ -754,17 +754,18 @@ private List<File> getChildren(File file) {
return file.listFiles().sort { File f -> f.name.toLowerCase() }
}
binding.setVariable("getCustomJDK", { File customJdkDir ->
getChildren(customJdkDir).each {
if (it.getName().endsWith(".tar.gz")) {
def customJdkFileName = it.getAbsolutePath().substring(0, it.getAbsolutePath().length() - 3)
if (new File(customJdkFileName).exists()){ ant.delete(file: customJdkFileName) }
if (new File("${home}/build/jdk/custom_jdk_${buildNumber}.tar").exists()){
ant.delete(file: "${home}/build/jdk/custom_jdk_${buildNumber}.tar")
binding.setVariable("getBundledJDK", { File jdkDir, String prefix, String ext, String bundledJDKFileName ->
getChildren(jdkDir).each {
if (it.getName().startsWith(prefix) && it.getName().endsWith(ext)) {
if (new File(bundledJDKFileName).exists()) { ant.delete(file: bundledJDKFileName) }
def JdkFileName = it.getAbsolutePath()
if (ext == ".tar.gz") {
JdkFileName = JdkFileName.substring(0, JdkFileName.length() - 3)
if (new File(JdkFileName).exists()) { ant.delete(file: JdkFileName) }
ant.gunzip(src: it.getAbsolutePath())
}
ant.gunzip(src: it.getAbsolutePath())
projectBuilder.info("customJdkFileName: " + customJdkFileName)
ant.copy(file: customJdkFileName, tofile: "${home}/build/jdk/custom_jdk_${buildNumber}.tar")
projectBuilder.info("JdkFileName: " + JdkFileName)
ant.copy(file: JdkFileName, tofile: bundledJDKFileName)
}
}
})
@@ -415,6 +415,9 @@ public class CompileDriver {
}
}
}
catch (ProcessCanceledException ignored) {
compileContext.putUserDataIfAbsent(COMPILE_SERVER_BUILD_STATUS, ExitStatus.CANCELLED);
}
catch (Throwable e) {
LOG.error(e); // todo
}
@@ -480,7 +483,7 @@ public class CompileDriver {
final Set<File> genSourceRoots = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
for (Module module : affectedModules) {
if (config.getAnnotationProcessingConfiguration(module).isEnabled()) {
if (!module.isDisposed() && config.getAnnotationProcessingConfiguration(module).isEnabled()) {
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
if (path != null) {
genSourceRoots.add(new File(path));
@@ -78,7 +78,7 @@ public class CompilerPathsEx extends CompilerPaths {
public static String[] getOutputPaths(Module[] modules) {
final Set<String> outputPaths = new OrderedSet<String>();
for (Module module : modules) {
final CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module);
final CompilerModuleExtension compilerModuleExtension = !module.isDisposed()? CompilerModuleExtension.getInstance(module) : null;
if (compilerModuleExtension == null) {
continue;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -143,7 +143,7 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
final JPanel evalFinallyPanel = new JPanel(new BorderLayout());
evalFinallyPanel.add(box, BorderLayout.CENTER);
evalFinallyPanel.add(new JLabel(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.on.pop")), BorderLayout.WEST);
panel.add(evalFinallyPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, cbLeftOffset, 0, 0), 0, 0));
panel.add(evalFinallyPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, cbLeftOffset, 0, 0), 0, 0));
return panel;
}
@@ -212,7 +212,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
private void flushArrayElementsOnUnknownIndexAssignment(PsiExpression lExpr) {
if (lExpr instanceof PsiArrayAccessExpression &&
myFactory.createValue(lExpr) == null // check for unknown index, otherwise AssignInstruction will flush only that element
!(myFactory.createValue(lExpr) instanceof DfaVariableValue) // check for unknown index, otherwise AssignInstruction will flush only that element
) {
DfaValue arrayVar = myFactory.createValue(((PsiArrayAccessExpression)lExpr).getArrayExpression());
if (arrayVar instanceof DfaVariableValue) {
@@ -70,13 +70,6 @@ public class DfaPsiUtil {
return Nullness.UNKNOWN;
}
if (NullableNotNullManager.isNullable(owner)) {
return Nullness.NULLABLE;
}
if (NullableNotNullManager.isNotNull(owner)) {
return Nullness.NOT_NULL;
}
if (resultType != null) {
NullableNotNullManager nnn = NullableNotNullManager.getInstance(owner.getProject());
for (PsiAnnotation annotation : resultType.getAnnotations()) {
@@ -95,6 +88,13 @@ public class DfaPsiUtil {
}
}
if (NullableNotNullManager.isNullable(owner)) {
return Nullness.NULLABLE;
}
if (NullableNotNullManager.isNotNull(owner)) {
return Nullness.NOT_NULL;
}
return Nullness.UNKNOWN;
}
@@ -74,7 +74,7 @@ public class StandardDataFlowRunner extends DataFlowRunner {
}
PsiType returnType = method.getReturnType();
return returnType != null && returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID);
return returnType != null && (returnType == PsiType.VOID || returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID));
}
public void onInstructionProducesCCE(Instruction instruction) {
@@ -70,6 +70,7 @@ public class DfaExpressionFactory {
return getExpressionDfaValue(((PsiParenthesizedExpression)expression).getExpression());
}
PsiType type = expression.getType();
if (expression instanceof PsiArrayAccessExpression) {
PsiExpression arrayExpression = ((PsiArrayAccessExpression)expression).getArrayExpression();
DfaValue qualifier = getExpressionDfaValue(arrayExpression);
@@ -79,7 +80,9 @@ public class DfaExpressionFactory {
return myFactory.getVarFactory().createVariableValue(indexVar, expression.getType(), false, (DfaVariableValue)qualifier);
}
}
return null;
if (type != null) {
return myFactory.createTypeValue(type, DfaPsiUtil.getElementNullability(type, null));
}
}
if (expression instanceof PsiMethodCallExpression) {
@@ -99,7 +102,6 @@ public class DfaExpressionFactory {
}
final Object value = JavaConstantExpressionEvaluator.computeConstantExpression(expression, false);
PsiType type = expression.getType();
if (value != null && type != null) {
if (value instanceof String) {
return myFactory.createTypeValue(type, Nullness.NOT_NULL); // Non-null string literal.
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -212,6 +212,7 @@ public class TargetElementUtil extends TargetElementUtilBase {
return null;
}
@NotNull
@Override
public Collection<PsiElement> getTargetCandidates(final PsiReference reference) {
PsiElement parent = reference.getElement().getParent();
@@ -15,7 +15,6 @@
*/
package com.intellij.psi.impl.source.codeStyle.javadoc;
import com.intellij.codeInsight.javadoc.JavaDocUtil;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.lang.ASTNode;
import com.intellij.lang.java.JavaLanguage;
@@ -31,9 +30,12 @@ import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.psi.impl.source.codeStyle.javadoc.JDParser.CommentInfo;
/**
* @author max
*/
@@ -63,47 +65,12 @@ public class CommentFormatter {
if (!getSettings().ENABLE_JAVADOC_FORMATTING) return;
PsiElement psiElement = SourceTreeToPsiMap.treeElementToPsi(element);
processElementComment(psiElement);
}
private void processElementComment(@Nullable PsiElement psiElement) {
if (psiElement instanceof PsiClass) {
String newCommentText = formatClassComment((PsiClass)psiElement);
replaceDocComment(newCommentText, (PsiDocCommentOwner)psiElement);
}
else if (psiElement instanceof PsiMethod) {
String newCommentText = formatMethodComment((PsiMethod)psiElement);
replaceDocComment(newCommentText, (PsiDocCommentOwner)psiElement);
}
else if (psiElement instanceof PsiField) {
String newCommentText = formatFieldComment((PsiField)psiElement);
replaceDocComment(newCommentText, (PsiDocCommentOwner)psiElement);
}
else if (psiElement instanceof PsiDocComment) {
PsiDocComment comment = (PsiDocComment)psiElement;
if (JavaDocUtil.isInsidePackageInfo(comment)) {
String newCommentText = formatPackageComment(comment);
replaceCommentText(newCommentText, comment);
} else {
processElementComment(psiElement.getParent());
}
if (psiElement != null) {
getParser().formatCommentText(psiElement, this);
}
}
private String formatPackageComment(@NotNull PsiDocComment comment) {
final String info = getCommentInfo(comment);
if (info == null) return null;
JDComment jdComment = getParser().parse(info, new JDComment(this));
return jdComment.generate("");
}
private void replaceDocComment(@Nullable String newCommentText, @NotNull final PsiDocCommentOwner psiDocCommentOwner) {
final PsiDocComment oldComment = psiDocCommentOwner.getDocComment();
replaceCommentText(newCommentText, oldComment);
}
private void replaceCommentText(@Nullable String newCommentText, @Nullable PsiDocComment oldComment) {
public void replaceCommentText(@Nullable String newCommentText, @Nullable PsiDocComment oldComment) {
if (newCommentText != null) newCommentText = stripSpaces(newCommentText);
if (newCommentText == null || oldComment == null || newCommentText.equals(oldComment.getText())) {
return;
@@ -142,53 +109,22 @@ public class CommentFormatter {
}
@Nullable
private String formatClassComment(@NotNull PsiClass psiClass) {
final String info = getOrigCommentInfo(psiClass);
if (info == null) return null;
JDComment comment = getParser().parse(info, new JDClassComment(this));
return comment.generate(getIndent(psiClass));
}
@Nullable
private String formatMethodComment(@NotNull PsiMethod psiMethod) {
final String info = getOrigCommentInfo(psiMethod);
if (info == null) return null;
JDComment comment = getParser().parse(info, new JDMethodComment(this));
return comment.generate(getIndent(psiMethod));
}
@Nullable
private String formatFieldComment(@NotNull PsiField psiField) {
final String info = getOrigCommentInfo(psiField);
if (info == null) return null;
JDComment comment = getParser().parse(info, new JDComment(this));
return comment.generate(getIndent(psiField));
}
/**
* Returns the original comment info of the specified element or null
*
* @param element the specified element
* @return text chunk
*/
@Nullable
private static String getOrigCommentInfo(PsiDocCommentOwner element) {
public static CommentInfo getOrigCommentInfo(PsiDocCommentOwner element) {
PsiElement e = element.getFirstChild();
if (!(e instanceof PsiComment)) {
//no comments for this element
return null;
}
else {
return getCommentInfo(((PsiComment)e));
return getCommentInfo((PsiComment)e);
}
}
@Nullable
private static String getCommentInfo(PsiComment element) {
public static CommentInfo getCommentInfo(PsiComment element) {
String commentHeader = null;
String commentFooter = null;
StringBuilder sb = new StringBuilder();
PsiElement e = element;
boolean first = true;
@@ -201,11 +137,18 @@ public class CommentFormatter {
sb.append(text.substring(2).trim());
}
else if (text.startsWith("/*")) {
if (text.charAt(2) == '*') {
text = text.substring(3, Math.max(3, text.length() - 2));
int commentHeaderEndOffset = CharArrayUtil.shiftForward(text, 1, "*");
int commentFooterStartOffset = CharArrayUtil.shiftBackward(text, text.length() - 2, "*");
if (commentHeaderEndOffset <= commentFooterStartOffset) {
commentHeader = text.substring(0, commentHeaderEndOffset);
commentFooter = text.substring(commentFooterStartOffset + 1);
text = text.substring(commentHeaderEndOffset, commentFooterStartOffset + 1);
}
else {
text = text.substring(2, Math.max(2, text.length() - 2));
commentHeader = text.substring(0, commentHeaderEndOffset);
text = "";
commentFooter = "";
}
sb.append(text);
}
@@ -217,7 +160,7 @@ public class CommentFormatter {
e = e.getNextSibling();
}
return sb.toString();
return new CommentInfo(commentHeader, sb.toString(), commentFooter);
}
/**
@@ -226,6 +169,9 @@ public class CommentFormatter {
* @return indentation size
*/
private int getIndentSpecial(@NotNull PsiElement element) {
if (element instanceof PsiDocComment) {
return 0;
}
LOG.assertTrue(element instanceof PsiClass ||
element instanceof PsiField ||
element instanceof PsiMethod);
@@ -252,7 +198,7 @@ public class CommentFormatter {
* @return indent which would be used for the given element when it's formatted according to the current code style settings
*/
@NotNull
private String getIndent(@NotNull PsiElement element) {
public String getIndent(@NotNull PsiElement element) {
return StringUtil.repeatSymbol(' ', getIndentSpecial(element));
}
}
@@ -37,6 +37,8 @@ public class JDComment {
private String mySince;
private String myDeprecated;
private boolean myMultiLineComment;
private String myFirstLine = "/**";
private String myEndLine = "*/";
public JDComment(@NotNull CommentFormatter formatter) {
myFormatter = formatter;
@@ -128,13 +130,13 @@ public class JDComment {
|| sb.indexOf("\n") != sb.length() - 1) // If comment has become multiline after formatting - it must be shown as multiline.
// Last symbol is always '\n', so we need to check if there is one more LF symbol before it.
{
sb.insert(0, "/**\n");
sb.insert(0, myFirstLine + '\n');
sb.append(indent);
} else {
sb.replace(0, prefix.length(), "/** ");
sb.deleteCharAt(sb.length()-1);
}
sb.append(" */");
sb.append(' ').append(myEndLine);
return sb.toString();
}
@@ -142,6 +144,14 @@ public class JDComment {
protected void generateSpecial(@NotNull String prefix, @NotNull StringBuilder sb) {
}
public void setFirstCommentLine(@NotNull String firstCommentLine) {
myFirstLine = firstCommentLine;
}
public void setLastCommentLine(@NotNull String lastCommentLine) {
myEndLine = lastCommentLine;
}
public void addSeeAlso(@NotNull String seeAlso) {
if (mySeeAlsoList == null) {
mySeeAlsoList = ContainerUtilRt.newArrayList();
@@ -19,7 +19,9 @@ import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.javadoc.PsiDocComment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,6 +42,8 @@ public class JDParser {
private static final String P_START_TAG = "<p>";
private static final String SELF_CLOSED_P_TAG = "<p/>";
private static final char lineSeparator = '\n';
private final CodeStyleSettings mySettings;
private final LanguageLevel myLanguageLevel;
@@ -48,11 +52,74 @@ public class JDParser {
myLanguageLevel = languageLevel;
}
private static final char lineSeparator = '\n';
public void formatCommentText(@NotNull PsiElement element, @NotNull CommentFormatter formatter) {
CommentInfo info = getElementsCommentInfo(element);
JDComment comment = info != null ? parse(info, formatter) : null;
if (comment != null) {
String indent = formatter.getIndent(info.getCommentOwner());
String commentText = comment.generate(indent);
formatter.replaceCommentText(commentText, (PsiDocComment)info.psiComment);
}
}
private CommentInfo getElementsCommentInfo(@Nullable PsiElement psiElement) {
CommentInfo info = null;
if (psiElement instanceof PsiDocComment) {
final PsiDocComment docComment = (PsiDocComment)psiElement;
if (docComment.getOwner() == null && docComment.getParent() instanceof PsiJavaFile) {
info = CommentFormatter.getCommentInfo(docComment);
if (info != null) {
info.setCommentOwner(docComment);
info.setComment(docComment);
}
}
else {
return getElementsCommentInfo(psiElement.getParent());
}
}
else if (psiElement instanceof PsiDocCommentOwner) {
PsiDocCommentOwner owner = (PsiDocCommentOwner)psiElement;
info = CommentFormatter.getOrigCommentInfo(owner);
if (info != null) {
info.setCommentOwner(owner);
info.setComment(owner.getDocComment());
}
}
return info;
}
private JDComment parse(@NotNull CommentInfo info, @NotNull CommentFormatter formatter) {
PsiElement owner = info.getCommentOwner();
JDComment comment = createComment(owner, formatter);
if (comment == null) return null;
parse(info.comment, comment);
if (info.commentHeader != null) {
comment.setFirstCommentLine(info.commentHeader);
}
if (info.commentFooter != null) {
comment.setLastCommentLine(info.commentFooter);
}
return comment;
}
private JDComment createComment(@NotNull PsiElement psiElement, @NotNull CommentFormatter formatter) {
if (psiElement instanceof PsiClass) {
return new JDClassComment(formatter);
}
else if (psiElement instanceof PsiMethod) {
return new JDMethodComment(formatter);
}
else if (psiElement instanceof PsiField || psiElement instanceof PsiDocComment) {
return new JDComment(formatter);
}
return null;
}
@NotNull
public JDComment parse(@Nullable String text, @NotNull JDComment comment) {
if (text == null) return comment;
private void parse(@Nullable String text, @NotNull JDComment comment) {
if (text == null) return;
List<Boolean> markers = new ArrayList<Boolean>();
List<String> l = toArray(text, "\n", markers);
@@ -66,9 +133,9 @@ public class JDParser {
comment.setMultiLine(true);
}
if (l == null) return comment;
if (l == null) return;
int size = l.size();
if (size == 0) return comment;
if (size == 0) return;
// preprocess strings - removes first '*'
for (int i = 0; i < size; i++) {
@@ -140,8 +207,6 @@ public class JDParser {
}
}
}
return comment;
}
/**
@@ -544,4 +609,35 @@ public class JDParser {
return sb;
}
public static class CommentInfo {
public final String commentHeader;
public final String comment;
public final String commentFooter;
private PsiComment psiComment;
private PsiElement myCommentOwner;
public CommentInfo(String commentHeader, String comment, String commentFooter) {
this.commentHeader = commentHeader;
this.comment = comment;
this.commentFooter = commentFooter;
}
public void setCommentOwner(PsiElement commentOwner) {
myCommentOwner = commentOwner;
}
public PsiElement getCommentOwner() {
return myCommentOwner;
}
public void setComment(PsiDocComment comment) {
psiComment = comment;
}
public PsiComment getComment() {
return psiComment;
}
}
}
@@ -42,7 +42,7 @@ public abstract class PsiTypeMapper extends PsiTypeVisitorEx<PsiType> {
PsiType mappedComponent = mapType(componentType);
if (mappedComponent == null) return null;
if (mappedComponent == componentType) return type;
return new PsiArrayType(mappedComponent);
return new PsiArrayType(mappedComponent, type.getAnnotations());
}
@Override
@@ -51,7 +51,7 @@ public abstract class PsiTypeMapper extends PsiTypeVisitorEx<PsiType> {
PsiType mappedComponent = mapType(componentType);
if (mappedComponent == null) return null;
if (mappedComponent == componentType) return type;
return new PsiEllipsisType(mappedComponent);
return new PsiEllipsisType(mappedComponent, type.getAnnotations());
}
@Override
@@ -0,0 +1,5 @@
package p;
import java.io.FileReader;
class MyReader extends FileReader {}
@@ -0,0 +1,11 @@
package p;
class Foo {
{
try (MyReader c1 = new MyReader() {}) {
}
}
}
@@ -0,0 +1,27 @@
import foo.*;
import java.util.List;
class TestCompilerWarnings {
public void m(@NotNull Object x) {
assert x != null;
}
public void test1Array(@Nullable String @NotNull [] x) {
if (<warning descr="Condition 'x == null' is always 'false'">x == null</warning>) {
System.out.println("x is null");
}
m(x);
m(<warning descr="Argument 'x[0]' might be null">x[0]</warning>);
}
public void test2Array(@NotNull String @Nullable [] x) {
if (x == null) {
System.out.println("x is null");
} else {
m(x[0]);
}
m(<warning descr="Argument 'x' might be null">x</warning>);
}
}
@@ -0,0 +1,12 @@
import org.jetbrains.annotations.Nullable;
class Example {
void foo() {
Runnable runnable = () -> bar();
}
@Nullable
String bar() {
return null;
}
}
@@ -16,6 +16,7 @@
package com.intellij.codeInsight;
import com.intellij.idea.Bombed;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ModifiableRootModel;
@@ -29,6 +30,8 @@ import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.*;
import com.intellij.util.Consumer;
import java.util.Calendar;
public class MultipleJdksHighlightingTest extends UsefulTestCase {
private CodeInsightTestFixture myFixture;
@@ -69,8 +72,7 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
ModuleRootModificationUtil.updateModel(myJava3Module, new Consumer<ModifiableRootModel>() {
@Override
public void consume(ModifiableRootModel model) {
model.addModuleOrderEntry(myJava7Module);
model.setSdk(IdeaTestUtil.getMockJdk17());
model.setSdk(IdeaTestUtil.getMockJdk14());
String contentUrl = VfsUtilCore.pathToUrl(myFixture.getTempDirPath()) + "/java3";
model.addContentEntry(contentUrl).addSourceFolder(contentUrl, false);
}
@@ -79,7 +81,6 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
ModuleRootModificationUtil.updateModel(myJava7Module, new Consumer<ModifiableRootModel>() {
@Override
public void consume(ModifiableRootModel model) {
model.addModuleOrderEntry(myJava8Module);
model.setSdk(IdeaTestUtil.getMockJdk17());
String contentUrl = VfsUtilCore.pathToUrl(myFixture.getTempDirPath()) + "/java7";
model.addContentEntry(contentUrl).addSourceFolder(contentUrl, false);
@@ -96,11 +97,18 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
});
}
private void addDependencies_37_78() {
ModuleRootModificationUtil.addDependency(myJava7Module, myJava8Module);
ModuleRootModificationUtil.addDependency(myJava3Module, myJava7Module);
}
public void testGetClass() throws Exception {
addDependencies_37_78();
doTest();
}
public void testWrongSuperInLibrary() throws Exception {
addDependencies_37_78();
final String name = getTestName(false);
for (Module module : new Module[] {myJava7Module, myJava8Module}) {
ModuleRootModificationUtil.updateModel(module, new Consumer<ModifiableRootModel>() {
@@ -116,42 +124,61 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
}
public void testWrongComparator() throws Exception {
addDependencies_37_78();
doTestWithoutLibrary();
}
public void testGenericComparator() throws Exception {
addDependencies_37_78();
doTestWithoutLibrary();
}
public void testGenericCallableWithDifferentTypeArgs() throws Exception {
addDependencies_37_78();
doTestWithoutLibrary();
}
public void testSuperclassImplementsUnknownType() throws Exception {
addDependencies_37_78();
doTestWithoutLibrary();
}
public void testDeclaredTypeOfVariableImplementsUnknownType() throws Exception {
addDependencies_37_78();
doTestWithoutLibrary();
}
public void testSuperclassImplementsGenericsOfUnknownType() throws Exception {
addDependencies_37_78();
doTestWithoutLibrary();
}
public void testSuperMethodNotExist() throws Exception {
addDependencies_37_78();
doTestWithoutLibrary();
}
public void testNoOverriding() throws Exception {
addDependencies_37_78();
doTestWithoutLibrary();
}
public void testStaticCallOnChildWithNotAccessibleParent() throws Exception {
addDependencies_37_78();
doTest3Modules();
}
@Bombed(user = "peter,anna", year = 2015, month = Calendar.MAY, day = 1)
public void testCloseableAutoCloseable() {
ModuleRootModificationUtil.addDependency(myJava7Module, myJava3Module);
final String name = getTestName(false);
myFixture.copyFileToProject("java3/p/" + name + ".java");
myFixture.configureByFiles("java7/p/" + name + ".java");
myFixture.checkHighlighting();
}
public void testLanguageLevelInReturnTypeCheck() throws Exception {
addDependencies_37_78();
final String name = getTestName(false);
myFixture.configureByFiles("java3/p/" + name + ".java", "java7/p/" + name + ".java");
myFixture.checkHighlighting();
@@ -77,9 +77,18 @@ public class DataFlowInspection8Test extends LightCodeInsightFixtureTestCase {
}
public void testMethodReferenceOnNullable() { doTest(); }
public void testNullableVoidLambda() { doTest(); }
public void testNullableForeachVariable() {
setupCustomAnnotations();
doTest();
}
public void testNullableArrayComponent() {
setupCustomAnnotations();
final DataFlowInspection inspection = new DataFlowInspection();
inspection.IGNORE_ASSERT_STATEMENTS = true;
myFixture.enableInspections(inspection);
myFixture.testHighlighting(true, false, true, getTestName(false) + ".java");
}
}
@@ -56,6 +56,61 @@ public class JavadocFormatterTest extends AbstractJavaFormatterTest {
);
}
public void test_do_wrap_on_asterisks() {
doTextTest(
"/***********\n" +
" *\n" +
" *********************/\n" +
"\n" +
"\n" +
" public class Test {\n" +
"}\n",
"/***********\n" +
" *\n" +
" *********************/\n" +
"\n" +
"\n" +
"public class Test {\n" +
"}\n"
);
}
public void test_wrap_after_asterisks() {
doTextTest(
"/******* hollla la\n" +
" * I am javadoc comment\n" +
" * heey ***********/\n" +
" class T { }\n",
"/*******\n" +
" * hollla la\n" +
" * I am javadoc comment\n" +
" * heey\n" +
" ***********/\n" +
"class T {\n" +
"}\n"
);
}
public void test_strange_comment() {
doTextTest(
"/******F*****/\n" +
"public class T {\n" +
"}",
"/******\n" +
" * F\n" +
" *****/\n" +
"public class T {\n" +
"}"
);
}
public void test_incomplete_javadoc() {
doTextTest(
"/**\n",
"/**\n"
);
}
public void testEA49739() throws Exception {
getSettings().WRAP_LONG_LINES = true;
getSettings().RIGHT_MARGIN = 35;
@@ -1,6 +1,10 @@
package com.intellij.util.indexing;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.psi.stubs.StubUpdatingIndex;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import com.intellij.util.text.CharArrayCharSequence;
/**
* @author Dmitry Avdeev
@@ -15,4 +19,14 @@ public class FileBasedIndexTest extends LightCodeInsightFixtureTestCase {
myFixture.configureByText("Bar.java", "class Bar { String bar; }");
myFixture.testHighlighting();
}
public void testLargeFile() throws Exception {
char[] text = new char[FileUtilRt.LARGE_FOR_CONTENT_LOADING + 42];
final String clazz = "class Foo { String bar; }";
for (int i = 0; i < text.length; i++) {
text[i] = i < clazz.length() ? clazz.charAt(i) : ' ';
}
final LightVirtualFile file = new LightVirtualFile("Foo.java", new CharArrayCharSequence(text));
assertFalse(((FileBasedIndexImpl)FileBasedIndex.getInstance()).isIndexingCandidate(file, StubUpdatingIndex.INDEX_ID));
}
}
@@ -1478,20 +1478,20 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
new1.getArrayDimensions().length == 0 &&
new1.getArrayInitializer() != null
) {
final MatchContext matchContext = myMatchingVisitor.getMatchContext();
final MatchingHandler handler = matchContext.getPattern().getHandler(classReference);
final boolean looseMatching = myMatchingVisitor.getMatchContext().getOptions().isLooseMatching();
final boolean typedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(classReference);
if ((typedVar || !looseMatching) && !allowsAbsenceOfMatch(classReference)) {
if ((handler instanceof SubstitutionHandler && ((SubstitutionHandler)handler).getMinOccurs() != 0) || !looseMatching) {
myMatchingVisitor.setResult(false);
return;
}
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(other.getProject());
final PsiType otherType = ((PsiVariable)other.getParent()).getType();
final PsiTypeElement otherTypeElement = factory.createTypeElement(otherType.getDeepComponentType());
final MatchContext matchContext = myMatchingVisitor.getMatchContext();
final MatchingHandler handler = matchContext.getPattern().getHandler(classReference);
if (handler instanceof SubstitutionHandler) {
final PsiType otherType = ((PsiArrayInitializerExpression)other).getType();
if (handler instanceof SubstitutionHandler && otherType != null) {
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(other.getProject());
final PsiTypeElement otherTypeElement = factory.createTypeElement(otherType.getDeepComponentType());
final SubstitutionHandler substitutionHandler = (SubstitutionHandler)handler;
myMatchingVisitor.setResult(substitutionHandler.handle(otherTypeElement, matchContext));
final MatchPredicate predicate = substitutionHandler.getPredicate();
myMatchingVisitor.setResult(predicate == null || predicate.match(null, otherTypeElement, matchContext));
}
else {
final PsiType type = new1.getType();
@@ -133,7 +133,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@Nullable ASTNode originalTree,
@Nullable MyTreeStructure parentLightTree) {
this(project, containingFile, parserDefinition.getWhitespaceTokens(), parserDefinition.getCommentTokens(), lexer, charTable, text,
originalTree, parentLightTree, 0);
originalTree, parentLightTree, null);
}
public PsiBuilderImpl(Project project,
@@ -145,7 +145,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@NotNull final CharSequence text,
@Nullable ASTNode originalTree,
@Nullable MyTreeStructure parentLightTree) {
this(project, containingFile, whiteSpaces, comments, lexer, charTable, text, originalTree, parentLightTree, 0);
this(project, containingFile, whiteSpaces, comments, lexer, charTable, text, originalTree, parentLightTree, null);
}
private PsiBuilderImpl(Project project,
@@ -157,7 +157,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@NotNull final CharSequence text,
@Nullable ASTNode originalTree,
@Nullable MyTreeStructure parentLightTree,
int offset) {
LazyParseableToken parentToken) {
myProject = project;
myFile = containingFile;
@@ -170,9 +170,9 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
myCharTable = charTable;
myOriginalTree = originalTree;
myParentLightTree = parentLightTree;
myOffset = offset;
myOffset = parentToken != null ? parentToken.getStartOffset() : 0;
cacheLexemes();
cacheLexemes(parentToken);
}
public PsiBuilderImpl(@NotNull final Project project,
@@ -190,10 +190,41 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@NotNull final LighterLazyParseableNode chameleon,
@NotNull final CharSequence text) {
this(project, chameleon.getContainingFile(), parserDefinition.getWhitespaceTokens(), parserDefinition.getCommentTokens(), lexer,
chameleon.getCharTable(), text, null, ((LazyParseableToken)chameleon).myParent, chameleon.getStartOffset());
chameleon.getCharTable(), text, null, ((LazyParseableToken)chameleon).myParent, ((LazyParseableToken)chameleon)
);
}
private void cacheLexemes() {
private void cacheLexemes(LazyParseableToken parentToken) {
int[] lexStarts = null;
IElementType[] lexTypes = null;
int lexemeCount = -1;
boolean doLexingOptimizationCorrectionCheck = false;
if (parentToken != null) {
// there are two types of lazy parseable tokens out there: collapsed out of individual tokens or single token that needs to be expanded
// in first case parent PsiBuilder has all our text lexed so no need to do it again
int tokenCount = parentToken.myEndIndex - parentToken.myStartIndex;
if (tokenCount != 1) { // not expand single lazy parseable token case
lexStarts = new int[tokenCount + 1];
System.arraycopy(parentToken.myBuilder.myLexStarts, parentToken.myStartIndex, lexStarts, 0, tokenCount);
int diff = parentToken.myBuilder.myLexStarts[parentToken.myStartIndex];
for(int i = 0; i < tokenCount; ++i) lexStarts[i] -= diff;
lexStarts[tokenCount] = myText.length();
lexTypes = new IElementType[tokenCount];
System.arraycopy(parentToken.myBuilder.myLexTypes, parentToken.myStartIndex, lexTypes, 0, tokenCount);
lexemeCount = tokenCount;
}
ProgressIndicatorProvider.checkCanceled();
if (!doLexingOptimizationCorrectionCheck) {
myLexStarts = lexStarts;
myLexTypes = lexTypes;
myLexemeCount = lexemeCount;
return;
}
}
int approxLexCount = Math.max(10, myText.length() / 5);
myLexStarts = new int[approxLexCount];
@@ -216,7 +247,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
final IElementType tokenType = myLexer.getTokenType();
sb.append("Token sequence broken")
.append("\n this: '").append(myLexer.getTokenText()).append("' (").append(tokenType).append(':')
.append(tokenType != null ? tokenType.getLanguage() : null).append(") ").append(tokenStart).append(":").append(myLexer.getTokenEnd());
.append(tokenType != null ? tokenType.getLanguage() : null).append(") ").append(tokenStart).append(":")
.append(myLexer.getTokenEnd());
if (i > 0) {
final int prevStart = myLexStarts[i - 1];
sb.append("\n prev: '").append(myText.subSequence(prevStart, offset)).append("' (").append(myLexTypes[i - 1]).append(':')
@@ -238,6 +270,19 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
myLexemeCount = i;
clearCachedTokenType();
//noinspection ConstantConditions
if (doLexingOptimizationCorrectionCheck) {
if (lexemeCount != -1) {
assert lexemeCount == myLexemeCount;
for(int j = 0; j < lexemeCount; ++j) {
if (myLexStarts[j] != lexStarts[j] || myLexTypes[j] != lexTypes[j]) {
assert false;
}
}
assert myLexStarts[lexemeCount] == lexStarts[lexemeCount];
}
}
}
@Override
@@ -1215,8 +1260,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
CharSequence context =
index < myLexStarts.length ? myText.subSequence(Math.max(0, myLexStarts[index] - 1000), myLexStarts[index]) : "<none>";
String language = myFile != null ? myFile.getLanguage() + ", " : "";
LOG.error(UNBALANCED_MESSAGE + "\n" +
"language: " + language + "\n" +
LOG.error(UNBALANCED_MESSAGE + "\n" +
"language: " + language + "\n" +
"context: '" + context + "'");
}
@@ -161,15 +161,18 @@ public class FoldingModelSupport {
private void addRange(int[] starts, int[] ends) {
List<FoldedBlock> result = new ArrayList<FoldedBlock>(3);
int[] rangeStarts = new int[myCount];
int[] rangeEnds = new int[myCount];
for (int number = 0; ; number++) {
int shift = getRangeShift(mySettings.range, number);
if (shift == -1) break;
for (int i = 0; i < myCount; i++) {
starts[i] = bound(starts[i] + shift, i);
ends[i] = bound(ends[i] - shift, i);
rangeStarts[i] = bound(starts[i] + shift, i);
rangeEnds[i] = bound(ends[i] - shift, i);
}
ContainerUtil.addAllNotNull(result, createRange(starts, ends, myExpandSuggester.isExpanded(starts, ends)));
ContainerUtil.addAllNotNull(result, createRange(rangeStarts, rangeEnds, myExpandSuggester.isExpanded(rangeStarts, rangeEnds)));
}
if (result.size() > 0) {
@@ -700,20 +703,17 @@ public class FoldingModelSupport {
//
/*
* number:
* 0: unchanged -> first folding
* 1: first folding-> second folding
* ...
* -1 - end
* number - depth of folding insertion (from zero)
* return: number of context lines. ('-1' - end)
*/
private static int getRangeShift(int range, int number) {
switch (number) {
case 0:
return range;
case 1:
return range;
case 2:
return range * 2;
case 2:
return range * 4;
default:
return -1;
}
@@ -37,6 +37,7 @@ import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.openapi.diagnostic.Logger;
@@ -822,7 +823,7 @@ public class DiffUtil {
public static WindowWrapper.Mode getWindowMode(@NotNull DiffDialogHints hints) {
WindowWrapper.Mode mode = hints.getMode();
if (mode == null) {
boolean isUnderDialog = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow() instanceof JDialog;
boolean isUnderDialog = LaterInvocator.isInModalContext();
mode = isUnderDialog ? WindowWrapper.Mode.MODAL : WindowWrapper.Mode.FRAME;
}
return mode;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -336,10 +336,11 @@ public class TargetElementUtilBase {
}
}
@NotNull
public Collection<PsiElement> getTargetCandidates(PsiReference reference) {
if (reference instanceof PsiPolyVariantReference) {
final ResolveResult[] results = ((PsiPolyVariantReference)reference).multiResolve(false);
final ArrayList<PsiElement> navigatableResults = new ArrayList<PsiElement>(results.length);
List<PsiElement> navigatableResults = new ArrayList<PsiElement>(results.length);
for(ResolveResult r:results) {
PsiElement element = r.getElement();
@@ -60,6 +60,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
@@ -345,6 +346,8 @@ public abstract class AbstractLayoutCodeProcessor {
try {
task.get();
}
catch (CancellationException ignored) {
}
catch (Exception e) {
LOG.error(e);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -558,7 +558,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
}
}
final PsiNameIdentifierOwner element = GotoDeclarationAction.findElementToShowUsagesOf(editor, file, offset);
final PsiNameIdentifierOwner element = GotoDeclarationAction.findElementToShowUsagesOf(editor, offset);
if (element != null) {
PsiElement identifier = element.getNameIdentifier();
return new Info(identifier){
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -83,8 +83,8 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration");
if (elements.length != 1) {
if (elements.length == 0) {
PsiElement element = findElementToShowUsagesOf(editor, file, editor.getCaretModel().getOffset());
if (elements.length == 0 && suggestCandidates(TargetElementUtilBase.findReference(editor, offset)).isEmpty()) {
PsiElement element = findElementToShowUsagesOf(editor, editor.getCaretModel().getOffset());
if (element != null) {
ShowUsagesAction showUsages = (ShowUsagesAction)ActionManager.getInstance().getAction(ShowUsagesAction.ID);
RelativePoint popupPosition = JBPopupFactory.getInstance().guessBestPopupLocation(editor);
@@ -111,7 +111,7 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
}
}
public static PsiNameIdentifierOwner findElementToShowUsagesOf(@NotNull Editor editor, @NotNull PsiFile file, int offset) {
public static PsiNameIdentifierOwner findElementToShowUsagesOf(@NotNull Editor editor, int offset) {
PsiElement elementAt = TargetElementUtilBase.getInstance().findTargetElement(editor, TargetElementUtilBase.ELEMENT_NAME_ACCEPTED, offset);
if (elementAt instanceof PsiNameIdentifierOwner) {
return (PsiNameIdentifierOwner)elementAt;
@@ -184,7 +184,8 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
return false;
}
private static Collection<PsiElement> suggestCandidates(final PsiReference reference) {
@NotNull
private static Collection<PsiElement> suggestCandidates(@Nullable PsiReference reference) {
if (reference == null) {
return Collections.emptyList();
}
@@ -325,12 +325,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
appendPairedInspectionsForUnfairTools(globalTools, globalSimpleTools, localTools);
((RefManagerImpl)getRefManager()).initializeAnnotators();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
runGlobalTools(scope, inspectionManager, globalTools);
}
});
runGlobalTools(scope, inspectionManager, globalTools);
if (runGlobalToolsOnly) return;
@@ -497,15 +492,16 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
return PsiDocumentManager.getInstance(getProject()).getDocument(file);
}
private void runGlobalTools(@NotNull AnalysisScope scope, @NotNull InspectionManager inspectionManager, @NotNull List<Tools> globalTools) {
private void runGlobalTools(@NotNull final AnalysisScope scope, @NotNull final InspectionManager inspectionManager, @NotNull List<Tools> globalTools) {
LOG.assertTrue(!ApplicationManager.getApplication().isReadAccessAllowed(), "Must not run under read action, too unresponsive");
final List<InspectionToolWrapper> needRepeatSearchRequest = new ArrayList<InspectionToolWrapper>();
final boolean surelyNoExternalUsages = scope.getScopeType() == AnalysisScope.PROJECT;
final boolean canBeExternalUsages = scope.getScopeType() != AnalysisScope.PROJECT;
for (Tools tools : globalTools) {
for (ScopeToolState state : tools.getTools()) {
InspectionToolWrapper toolWrapper = state.getTool();
GlobalInspectionTool tool = (GlobalInspectionTool)toolWrapper.getTool();
InspectionToolPresentation toolPresentation = getPresentation(toolWrapper);
final InspectionToolWrapper toolWrapper = state.getTool();
final GlobalInspectionTool tool = (GlobalInspectionTool)toolWrapper.getTool();
final InspectionToolPresentation toolPresentation = getPresentation(toolWrapper);
try {
if (tool.isGraphNeeded()) {
try {
@@ -516,11 +512,17 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
throw e;
}
}
tool.runInspection(scope, inspectionManager, this, toolPresentation);
//skip phase when we are sure that scope already contains everything
if (!surelyNoExternalUsages && tool.queryExternalUsagesRequests(inspectionManager, this, toolPresentation)) {
needRepeatSearchRequest.add(toolWrapper);
}
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
tool.runInspection(scope, inspectionManager, GlobalInspectionContextImpl.this, toolPresentation);
//skip phase when we are sure that scope already contains everything
if (canBeExternalUsages &&
tool.queryExternalUsagesRequests(inspectionManager, GlobalInspectionContextImpl.this, toolPresentation)) {
needRepeatSearchRequest.add(toolWrapper);
}
}
});
}
catch (ProcessCanceledException e) {
throw e;
@@ -2456,14 +2456,14 @@ public class FileBasedIndexImpl extends FileBasedIndex {
private boolean isTooLarge(@NotNull VirtualFile file) {
if (SingleRootFileViewProvider.isTooLargeForIntelligence(file)) {
return !myNoLimitCheckTypes.contains(file.getFileType()) && !SingleRootFileViewProvider.isTooLargeForContentLoading(file);
return !myNoLimitCheckTypes.contains(file.getFileType()) || SingleRootFileViewProvider.isTooLargeForContentLoading(file);
}
return false;
}
private boolean isTooLarge(@NotNull VirtualFile file, long contentSize) {
if (SingleRootFileViewProvider.isTooLargeForIntelligence(file, contentSize)) {
return !myNoLimitCheckTypes.contains(file.getFileType()) && !SingleRootFileViewProvider.isTooLargeForContentLoading(file, contentSize);
return !myNoLimitCheckTypes.contains(file.getFileType()) || SingleRootFileViewProvider.isTooLargeForContentLoading(file, contentSize);
}
return false;
}
@@ -269,7 +269,7 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica
runnable.run();
}
catch (Throwable e) {
LOG.error(e);
LOG.error("Error executing task " + runnable, e);
}
}
}
@@ -15,28 +15,63 @@
*/
package com.intellij.openapi.wm.impl.welcomeScreen;
import com.intellij.ide.ProjectGroupActionGroup;
import com.intellij.ide.ReopenProjectAction;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.project.DumbAwareAction;
import java.awt.event.InputEvent;
import java.util.List;
/**
* @author Konstantin Bulenkov
*/
public class OpenSelectedProjectsAction extends DumbAwareAction {
public class OpenSelectedProjectsAction extends RecentProjectsWelcomeScreenActionBase {
@Override
public void actionPerformed(AnActionEvent e) {
List<AnAction> elements = getSelectedElements(e);
e = new AnActionEvent(e.getInputEvent(), e.getDataContext(), e.getPlace(), e.getPresentation(), e.getActionManager(), InputEvent.SHIFT_MASK);
for (AnAction element : elements) {
if (element instanceof ProjectGroupActionGroup) {
for (AnAction action : ((ProjectGroupActionGroup)element).getChildren(e)) {
action.actionPerformed(e);
}
} else {
element.actionPerformed(e);
}
}
}
@Override
public void update(AnActionEvent e) {
final Presentation presentation = e.getPresentation();
List<AnAction> selectedElements = getSelectedElements(e);
boolean hasProject = false;
boolean hasGroup = false;
for (AnAction element : selectedElements) {
if (element instanceof ReopenProjectAction) {
hasProject = true;
}
if (element instanceof ProjectGroupActionGroup) {
hasGroup = true;
}
if (hasGroup && hasProject) {
e.getPresentation().setEnabled(false);
return;
}
}
if (ActionPlaces.WELCOME_SCREEN.equals(e.getPlace())) {
presentation.setEnabledAndVisible(true);
presentation.setText("Open Selected");
return;
if (selectedElements.size() == 1 && selectedElements.get(0) instanceof ProjectGroupActionGroup) {
presentation.setText("Open All Projects in Group");
} else {
presentation.setText("Open Selected");
}
} else {
presentation.setEnabledAndVisible(false);
}
presentation.setEnabledAndVisible(false);
}
}
@@ -270,7 +270,7 @@ public class EditorComboBox extends JComboBox implements DocumentListener {
@Override
public void setItem(Object anObject) {
if (anObject != null) {
EditorComboBox.this.setText((String)anObject);
EditorComboBox.this.setText(anObject.toString());
} else {
EditorComboBox.this.setText("");
}
@@ -551,13 +551,36 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
String s9 = "int a[] = new int[] { 1,2,3,4};\n" +
"int b[] = { 2,3,4,5 };\n" +
"Object[] c = new Object[] { \"\", null};";
"Object[] c = new Object[] { \"\", null};\n" +
"Object[] d = {null, null};\n" +
"Object[] e = {};\n" +
"Object[] f = new Object[]{}\n" +
"String[] g = new String[]{}\n" +
"String[] h = new String[]{new String()}";
assertEquals("Find array instantiation 1", 2, findMatchesCount(s9, "new '_ []{ '_* }"));
assertEquals("Find array instantiation 2", 2, findMatchesCount(s9, "new int []{ '_* }"));
assertEquals("Find array instantiation 3", 2, findMatchesCount(s9, "new 'a?:int [] { '_* }"));
assertEquals("Find array instantiation 4", 3, findMatchesCount(s9, "new '_? []{ '_* }"));
assertEquals("Find array instantiation 5", 1, findMatchesCount(s9, "new Object[] { '_* }"));
assertEquals("Find new array expressions, but no array initializer expressions", 5,
findMatchesCount(s9, "new '_ []{ '_* }"));
assertEquals("Find new int array expressions, including array initializer expressions", 2,
findMatchesCount(s9, "new int []{ '_* }"));
assertEquals("Find new int array expressions, including array initializer expressions using variable ", 2,
findMatchesCount(s9, "new 'a?:int [] { '_* }"));
assertEquals("Find all new array expressions, including array initializers", 8,
findMatchesCount(s9, "new '_? []{ '_* }"));
assertEquals("Find new Object array expressions, including array initializer expressions", 4,
findMatchesCount(s9, "new Object[] { '_* }"));
assertEquals("Find only array initializer expressions", 3,
findMatchesCount(s9, "new '_{0,0}[] { '_* }"));
assertEquals("Find only int array initializer expressions", 1,
findMatchesCount(s9, "new '_{0,0}:int [] { '_* }"));
assertEquals("Try to find String array initializer expressions", 0,
findMatchesCount(s9, "new '_{0,0}:String [] { '_* }"));
}
public void testLiteral() {
@@ -21,6 +21,7 @@ import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.containers.WeakList;
import org.jetbrains.annotations.NotNull;
import javax.management.ListenerNotFoundException;
import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationListener;
@@ -66,6 +67,21 @@ public class LowMemoryWatcher {
}
}
};
private static final NotificationListener ourLowMemoryListener = new NotificationListener() {
@Override
public void handleNotification(Notification n, Object hb) {
if (MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED.equals(n.getType()) ||
MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED.equals(n.getType())) {
synchronized (ourJanitor) {
if (!ourSubmitted) {
//noinspection AssignmentToStaticFieldFromInstanceMethod
ourSubmitted = true;
ourExecutor.submit(ourJanitor);
}
}
}
}
};
private final Runnable myRunnable;
@@ -79,20 +95,7 @@ public class LowMemoryWatcher {
}
}
}
((NotificationEmitter)ManagementFactory.getMemoryMXBean()).addNotificationListener(new NotificationListener() {
@Override
public void handleNotification(Notification n, Object hb) {
if (MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED.equals(n.getType()) || MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED.equals(n.getType())) {
synchronized (ourJanitor) {
if (!ourSubmitted) {
//noinspection AssignmentToStaticFieldFromInstanceMethod
ourSubmitted = true;
ourExecutor.submit(ourJanitor);
}
}
}
}
}, null, null);
((NotificationEmitter)ManagementFactory.getMemoryMXBean()).addNotificationListener(ourLowMemoryListener, null, null);
}
/**
@@ -135,6 +138,12 @@ public class LowMemoryWatcher {
public static void stopAll() {
ourExecutor.shutdown();
ourInstances.clear();
try {
((NotificationEmitter)ManagementFactory.getMemoryMXBean()).removeNotificationListener(ourLowMemoryListener);
}
catch (ListenerNotFoundException e) {
LOG.error(e);
}
}
}
@@ -64,6 +64,7 @@ import com.intellij.ui.content.ContentManager;
import com.intellij.ui.dualView.*;
import com.intellij.ui.table.TableView;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.*;
import org.jetbrains.annotations.NonNls;
@@ -764,12 +765,13 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton {
final MyDiffAction diffAction = new MyDiffAction();
result.add(diffAction);
if (!popup) {
diffAction.registerCustomShortcutSet(new CustomShortcutSet(
CommonShortcuts.getDiff().getShortcuts() [0],
CommonShortcuts.DOUBLE_CLICK_1.getShortcuts() [0]), myDualView.getFlatView());
diffAction.registerCustomShortcutSet(new CustomShortcutSet(
CommonShortcuts.getDiff().getShortcuts() [0],
CommonShortcuts.DOUBLE_CLICK_1.getShortcuts() [0]), myDualView.getTreeView());
List<Shortcut> shortcuts = new SmartList<Shortcut>();
ContainerUtil.addAll(shortcuts, CommonShortcuts.getDiff().getShortcuts());
ContainerUtil.addAll(shortcuts, CommonShortcuts.DOUBLE_CLICK_1.getShortcuts());
CustomShortcutSet shortcutSet = new CustomShortcutSet(ContainerUtil.toArray(shortcuts, new Shortcut[shortcuts.size()]));
diffAction.registerCustomShortcutSet(shortcutSet, myDualView.getFlatView());
diffAction.registerCustomShortcutSet(shortcutSet, myDualView.getTreeView());
}
else {
diffAction.registerCustomShortcutSet(CommonShortcuts.getDiff(), this);
@@ -1,3 +1,18 @@
/*
* Copyright 2000-2015 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.xdebugger.impl.settings;
import com.intellij.openapi.options.Configurable;
@@ -121,7 +136,7 @@ class MergedCompositeConfigurable implements SearchableConfigurable {
@NotNull
static JPanel createPanel(boolean isUseTitledBorder) {
int verticalGap = TitledSeparator.TOP_INSET;
JPanel panel = new JPanel(new VerticalFlowLayout(0, isUseTitledBorder ? 0 : verticalGap));
JPanel panel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, isUseTitledBorder ? 0 : verticalGap, true, true));
// VerticalFlowLayout incorrectly use vertical gap as top inset
if (!isUseTitledBorder) {
panel.setBorder(new EmptyBorder(-verticalGap, 0, 0, 0));
+1
View File
@@ -157,6 +157,7 @@
<projectService
serviceInterface="git4idea.config.GitVcsSettings"
serviceImplementation="git4idea.config.GitVcsSettings"/>
<projectService serviceImplementation="git4idea.config.GitRebaseSettings"/>
<projectService serviceImplementation="git4idea.config.GitSharedSettings" />
<projectService
serviceInterface="git4idea.config.GitExecutableValidator"
@@ -17,16 +17,17 @@ package git4idea.actions;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsNotifier;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.GitUtil;
import git4idea.commands.Git;
import git4idea.commands.GitCommandResult;
import git4idea.commands.GitLineHandler;
import git4idea.commands.GitTask;
import git4idea.commands.GitTaskResult;
import git4idea.commands.GitTaskResultHandlerAdapter;
import git4idea.i18n.GitBundle;
import git4idea.rebase.GitInteractiveRebaseEditorHandler;
import git4idea.rebase.GitRebaseEditorService;
@@ -50,7 +51,7 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
@NotNull final VirtualFile defaultRoot,
final Set<VirtualFile> affectedRoots,
final List<VcsException> exceptions) throws VcsException {
GitLineHandler h = createHandler(project, gitRoots, defaultRoot);
final GitLineHandler h = createHandler(project, gitRoots, defaultRoot);
if (h == null) {
return;
}
@@ -63,34 +64,32 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
affectedRoots.add(root);
service.configureHandler(h, editor.getHandlerNo());
GitTask task = new GitTask(project, h, GitBundle.getString("rebasing.title"));
task.executeInBackground(false, new GitTaskResultHandlerAdapter() {
new Task.Backgroundable(project, GitBundle.getString("rebasing.title"), false) {
@Override
protected void run(GitTaskResult taskResult) {
public void run(@NotNull ProgressIndicator indicator) {
AccessToken token = DvcsUtil.workingTreeChangeStarted(project);
try {
GitCommandResult result = ServiceManager.getService(Git.class).runCommand(h);
editor.close();
GitRepositoryManager manager = GitUtil.getRepositoryManager(project);
manager.updateRepository(root);
root.refresh(false, true);
notifyAboutResult(taskResult, resultListener, exceptions, project);
notifyAboutResult(result, resultListener, exceptions, project);
}
finally {
DvcsUtil.workingTreeChangeFinished(project, token);
}
}
});
}.queue();
}
private static void notifyAboutResult(GitTaskResult taskResult,
GitRebaseLineListener resultListener,
List<VcsException> exceptions,
Project project) {
if (taskResult == GitTaskResult.CANCELLED) {
return;
}
private static void notifyAboutResult(@NotNull GitCommandResult commandResult,
@NotNull GitRebaseLineListener resultListener,
@NotNull List<VcsException> exceptions,
@NotNull Project project) {
final GitRebaseLineListener.Result result = resultListener.getResult();
String messageId;
String message = null;
boolean isError = true;
switch (result.status) {
case CONFLICT:
@@ -98,6 +97,7 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
break;
case ERROR:
messageId = "rebase.result.error";
message = commandResult.getErrorOutputAsHtmlString();
break;
case CANCELLED:
// we do not need to show a message if editing was cancelled.
@@ -112,18 +112,12 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
messageId = "rebase.result.success";
break;
default:
messageId = null;
throw new IllegalStateException("Unsupported rebase result: " + result.status);
}
String message;
String title;
if (messageId != null) {
String title = GitBundle.message(messageId + ".title");
if (message == null) {
message = GitBundle.message(messageId, result.current, result.total);
title = GitBundle.message(messageId + ".title");
}
else {
message = "Rebase finished: " + StringUtil.capitalize(StringUtil.toLowerCase(result.status.name()));
title = "";
}
if (isError) {
@@ -42,6 +42,14 @@ public interface Git {
@NotNull
GitCommandResult runCommand(@NotNull Computable<GitLineHandler> handlerConstructor);
/**
* A generic method to run a Git command, when existing methods are not sufficient. <br/>
* Can be used instead of {@link #runCommand(Computable)} if the operation will not need to be repeated for sure
* (e.g. it is a completely local operation).
*/
@NotNull
GitCommandResult runCommand(@NotNull GitLineHandler handler);
@NotNull
GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners);
@@ -47,6 +47,7 @@ import static java.util.Collections.singleton;
*
* @author Kirill Likhodedov
*/
@SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale")
public class GitImpl implements Git {
private final Logger LOG = Logger.getInstance(Git.class);
@@ -624,13 +625,24 @@ public class GitImpl implements Git {
public GitCommandResult runCommand(@NotNull Computable<GitLineHandler> handlerConstructor) {
return run(handlerConstructor);
}
@NotNull
@Override
public GitCommandResult runCommand(@NotNull final GitLineHandler handler) {
return runCommand(new Computable<GitLineHandler>() {
@Override
public GitLineHandler compute() {
return handler;
}
});
}
/**
* Check if the line looks line an error message
*/
private static boolean isError(String text) {
for (String indicator : ERROR_INDICATORS) {
if (text.startsWith(indicator.toLowerCase())) {
if (text.trim().toLowerCase().startsWith(indicator.toLowerCase())) {
return true;
}
}
@@ -640,7 +652,7 @@ public class GitImpl implements Git {
// could be upper-cased, so should check case-insensitively
public static final String[] ERROR_INDICATORS = {
"error", "remote: error", "fatal",
"Cannot apply", "Could not", "Interactive rebase already started", "refusing to pull", "cannot rebase:", "conflict",
"Cannot", "Could not", "Interactive rebase already started", "refusing to pull", "cannot rebase:", "conflict",
"unable"
};
}
@@ -0,0 +1,89 @@
/*
* Copyright 2000-2015 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.config;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
import org.jetbrains.annotations.Nullable;
@State(name = "Git.Rebase.Settings", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
public class GitRebaseSettings implements PersistentStateComponent<GitRebaseSettings.State> {
private State myState = new State();
public static class State {
public boolean INTERACTIVE = true;
public boolean PRESERVE_MERGES = false;
public boolean SHOW_TAGS = false;
public boolean SHOW_REMOTE_BRANCHES = false;
public String ONTO = null;
}
@Nullable
@Override
public State getState() {
return myState;
}
@Override
public void loadState(State state) {
myState = state;
}
public boolean isInteractive() {
return myState.INTERACTIVE;
}
public void setInteractive(boolean interactive) {
myState.INTERACTIVE = interactive;
}
public boolean isPreserveMerges() {
return myState.PRESERVE_MERGES;
}
public void setPreserveMerges(boolean preserveMerges) {
myState.PRESERVE_MERGES = preserveMerges;
}
public boolean showTags() {
return myState.SHOW_TAGS;
}
public void setShowTags(boolean showTags) {
myState.SHOW_TAGS = showTags;
}
public boolean showRemoteBranches() {
return myState.SHOW_REMOTE_BRANCHES;
}
public void setShowRemoteBranches(boolean showRemoteBranches) {
myState.SHOW_REMOTE_BRANCHES = showRemoteBranches;
}
@Nullable
public String getOnto() {
return myState.ONTO;
}
public void setOnto(@Nullable String onto) {
myState.ONTO = onto;
}
}
@@ -290,7 +290,6 @@ rebase.result.cancelled=The rebase process was cancelled.
rebase.result.conflict.title=Rebase Suspended
rebase.result.conflict=Stopped rebasing because of conflict ({0}/{1}).\nResolve conflicts and continue the rebase process.
rebase.result.error.title=Rebase Error
rebase.result.error=Stopped rebasing because of error while rebasing ({0}/{1}).\nCheck vcs console for details.
rebase.show.remote.branches.tooltip=If selected, remote branches are shown in drop down as well.
rebase.show.remote.branches=Show Re&mote Branches
rebase.show.tags.tooltip=Show tags in \"from\" and \"onto\" comboboxes.
@@ -15,8 +15,10 @@
*/
package git4idea.rebase;
import com.intellij.CommonBundle;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.UIUtil;
@@ -24,6 +26,7 @@ import git4idea.commands.GitHandler;
import org.jetbrains.annotations.NotNull;
import java.io.Closeable;
import java.util.List;
/**
* The handler for rebase editor request. The handler shows {@link git4idea.rebase.GitRebaseEditor}
@@ -110,21 +113,33 @@ public class GitInteractiveRebaseEditorHandler implements Closeable, GitRebaseEd
isSuccess.set(true);
return;
}
else {
isSuccess.set(false);
}
}
else {
setRebaseEditorShown();
GitRebaseEditor editor = new GitRebaseEditor(myProject, myRoot, path);
if (editor.showAndGet()) {
editor.save();
isSuccess.set(true);
return;
GitInteractiveRebaseFile rebaseFile = new GitInteractiveRebaseFile(myProject, myRoot, path);
try {
List<GitRebaseEntry> entries = rebaseFile.load();
GitRebaseEditor editor = new GitRebaseEditor(myProject, myRoot, entries);
if (editor.showAndGet()) {
rebaseFile.save(editor.getEntries());
isSuccess.set(true);
return;
}
else {
rebaseFile.cancel();
}
}
else {
editor.cancel();
isSuccess.set(true);
catch (GitInteractiveRebaseFile.NoopException e) {
LOG.info("Noop situation while rebasing " + myRoot);
String message = "There are no commits to rebase because the current branch is directly below the base branch " +
"(the 'noop' situation).\n" +
"Do you want to continue (this will reset the current branch to the base branch)?";
int rebase = Messages.showOkCancelDialog(myProject, message, "Git Rebase", CommonBundle.getOkButtonText(),
CommonBundle.getCancelButtonText(), Messages.getQuestionIcon());
if (rebase == Messages.OK) {
isSuccess.set(true);
return;
}
}
}
}
@@ -0,0 +1,108 @@
/*
* Copyright 2000-2015 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.rebase;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import git4idea.config.GitConfigUtil;
import git4idea.util.StringScanner;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.io.*;
import java.util.List;
class GitInteractiveRebaseFile {
@NonNls private static final String CYGDRIVE_PREFIX = "/cygdrive/";
@NotNull private final Project myProject;
@NotNull private final VirtualFile myRoot;
@NotNull private final String myFile;
GitInteractiveRebaseFile(@NotNull Project project, @NotNull VirtualFile root, @NotNull String rebaseFilePath) {
myProject = project;
myRoot = root;
myFile = adjustFilePath(rebaseFilePath);
}
@NotNull
public List<GitRebaseEntry> load() throws IOException, NoopException {
String encoding = GitConfigUtil.getLogEncoding(myProject, myRoot);
List<GitRebaseEntry> entries = ContainerUtil.newArrayList();
final StringScanner s = new StringScanner(FileUtil.loadFile(new File(myFile), encoding));
boolean noop = false;
while (s.hasMoreData()) {
if (s.isEol() || s.startsWith('#')) {
s.nextLine();
continue;
}
if (s.startsWith("noop")) {
noop = true;
s.nextLine();
continue;
}
String action = s.spaceToken();
String hash = s.spaceToken();
String comment = s.line();
entries.add(new GitRebaseEntry(action, hash, comment));
}
if (noop && entries.isEmpty()) {
throw new NoopException();
}
return entries;
}
public void cancel() throws IOException {
PrintWriter out = new PrintWriter(new FileWriter(myFile));
try {
out.println("# rebase is cancelled");
}
finally {
out.close();
}
}
public void save(@NotNull List<GitRebaseEntry> entries) throws IOException {
String encoding = GitConfigUtil.getLogEncoding(myProject, myRoot);
PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(myFile), encoding));
try {
for (GitRebaseEntry e : entries) {
if (e.getAction() != GitRebaseEntry.Action.skip) {
out.println(e.getAction().toString() + " " + e.getCommit() + " " + e.getSubject());
}
}
}
finally {
out.close();
}
}
@NotNull
private static String adjustFilePath(@NotNull String file) {
if (SystemInfo.isWindows && file.startsWith(CYGDRIVE_PREFIX)) {
final int prefixSize = CYGDRIVE_PREFIX.length();
return file.substring(prefixSize, prefixSize + 1) + ":" + file.substring(prefixSize + 1);
}
return file;
}
static class NoopException extends Exception {
}
}
@@ -15,10 +15,12 @@
*/
package git4idea.rebase;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.DocumentAdapter;
@@ -27,12 +29,15 @@ import git4idea.branch.GitBranchUtil;
import git4idea.commands.GitCommand;
import git4idea.commands.GitLineHandler;
import git4idea.config.GitConfigUtil;
import git4idea.config.GitRebaseSettings;
import git4idea.i18n.GitBundle;
import git4idea.merge.GitMergeUtil;
import git4idea.repo.GitRemote;
import git4idea.repo.GitRepository;
import git4idea.ui.GitReferenceValidator;
import git4idea.util.GitUIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
@@ -115,7 +120,7 @@ public class GitRebaseDialog extends DialogWrapper {
/**
* The current branch
*/
protected GitBranch myCurrentBranch;
@Nullable protected GitBranch myCurrentBranch;
/**
* The tags
*/
@@ -128,6 +133,9 @@ public class GitRebaseDialog extends DialogWrapper {
* The validator for from field
*/
private final GitReferenceValidator myFromValidator;
@NotNull private final GitRebaseSettings mySettings;
@Nullable private final String myOriginalOntoBranch;
/**
* A constructor
@@ -142,6 +150,7 @@ public class GitRebaseDialog extends DialogWrapper {
setOKButtonText(GitBundle.getString("rebase.button"));
init();
myProject = project;
mySettings = ServiceManager.getService(myProject, GitRebaseSettings.class);
final Runnable validateRunnable = new Runnable() {
public void run() {
validateFields();
@@ -157,11 +166,50 @@ public class GitRebaseDialog extends DialogWrapper {
validateFields();
}
});
setupBranches();
setupStrategy();
myInteractiveCheckBox.setSelected(mySettings.isInteractive());
myPreserveMergesCheckBox.setSelected(mySettings.isPreserveMerges());
myShowTagsCheckBox.setSelected(mySettings.showTags());
myShowRemoteBranchesCheckBox.setSelected(mySettings.showRemoteBranches());
overwriteOntoForCurrentBranch(mySettings);
myOriginalOntoBranch = GitUIUtil.getTextField(myOntoComboBox).getText();
validateFields();
}
@Nullable
@Override
public JComponent getPreferredFocusedComponent() {
return myOntoComboBox;
}
private void overwriteOntoForCurrentBranch(@NotNull GitRebaseSettings settings) {
String onto = settings.getOnto();
if (onto != null && !onto.equals(myBranchComboBox.getSelectedItem())) {
if (!isValidRevision(onto)) {
mySettings.setOnto(null);
}
else {
myOntoComboBox.setSelectedItem(onto);
}
}
}
private boolean isValidRevision(@NotNull String revisionExpression) {
try {
GitRevisionNumber.resolve(myProject, gitRoot(), revisionExpression);
return true;
}
catch (VcsException e) {
LOG.debug(e);
return false;
}
}
public GitLineHandler handler() {
GitLineHandler h = new GitLineHandler(myProject, gitRoot(), GitCommand.REBASE);
h.setStdoutSuppressed(false);
@@ -195,6 +243,27 @@ public class GitRebaseDialog extends DialogWrapper {
return h;
}
@Override
protected void doOKAction() {
try {
rememberFields();
}
finally {
super.doOKAction();
}
}
private void rememberFields() {
mySettings.setInteractive(myInteractiveCheckBox.isSelected());
mySettings.setPreserveMerges(myPreserveMergesCheckBox.isSelected());
mySettings.setShowTags(myShowTagsCheckBox.isSelected());
mySettings.setShowRemoteBranches(myShowRemoteBranchesCheckBox.isSelected());
String onto = StringUtil.nullize(GitUIUtil.getTextField(myOntoComboBox).getText(), true);
if (onto != null && !onto.equals(myOriginalOntoBranch)) {
mySettings.setOnto(onto);
}
}
/**
* Setup strategy
*/
@@ -17,12 +17,12 @@ package git4idea.rebase;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.Cell;
import com.intellij.ui.ColoredTableCellRenderer;
import com.intellij.ui.TableSpeedSearch;
import com.intellij.ui.speedSearch.SpeedSearchUtil;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ListWithSelection;
@@ -31,10 +31,8 @@ import com.intellij.util.ui.ComboBoxTableCellRenderer;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import git4idea.GitUtil;
import git4idea.config.GitConfigUtil;
import git4idea.i18n.GitBundle;
import git4idea.util.StringScanner;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -46,8 +44,7 @@ import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.ArrayList;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -81,45 +78,21 @@ public class GitRebaseEditor extends DialogWrapper {
* Table model
*/
private final MyTableModel myTableModel;
/**
* The file name
*/
private final String myFile;
/**
* The project
*/
private final Project myProject;
/**
* The git root
*/
private final VirtualFile myGitRoot;
/**
* The cygwin drive prefix
*/
@NonNls private static final String CYGDRIVE_PREFIX = "/cygdrive/";
/**
* The constructor
*
* @param project the project
* @param gitRoot the git root
* @param file the file to edit
* @param entries the file to edit
* @throws IOException if file could not be loaded
*/
protected GitRebaseEditor(final Project project, final VirtualFile gitRoot, String file) throws IOException {
protected GitRebaseEditor(final Project project, final VirtualFile gitRoot, List<GitRebaseEntry> entries) throws IOException {
super(project, true);
myProject = project;
myGitRoot = gitRoot;
setTitle(GitBundle.getString("rebase.editor.title"));
setOKButtonText(GitBundle.getString("rebase.editor.button"));
if (SystemInfo.isWindows && file.startsWith(CYGDRIVE_PREFIX)) {
final int prefixSize = CYGDRIVE_PREFIX.length();
file = file.substring(prefixSize, prefixSize + 1) + ":" + file.substring(prefixSize + 1);
}
myFile = file;
myTableModel = new MyTableModel();
myTableModel.load(file);
myTableModel = new MyTableModel(entries);
myCommitsTable.setModel(myTableModel);
myCommitsTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
myCommitsTable.setIntercellSpacing(JBUI.emptySize());
@@ -132,6 +105,14 @@ public class GitRebaseEditor extends DialogWrapper {
actionColumn.setCellEditor(new DefaultCellEditor(editorComboBox));
actionColumn.setCellRenderer(ComboBoxTableCellRenderer.INSTANCE);
myCommitsTable.setDefaultRenderer(String.class, new ColoredTableCellRenderer() {
@Override
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
append(value.toString());
SpeedSearchUtil.applySpeedSearchHighlighting(myCommitsTable, this, true, selected);
}
});
myCommitsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(final ListSelectionEvent e) {
myViewButton.setEnabled(myCommitsTable.getSelectedRowCount() == 1);
@@ -215,15 +196,6 @@ public class GitRebaseEditor extends DialogWrapper {
setOKActionEnabled(true);
}
/**
* Save entries back to the file
*
* @throws IOException if there is IO problem with saving
*/
public void save() throws IOException {
myTableModel.save(myFile);
}
/**
* {@inheritDoc}
*/
@@ -247,13 +219,9 @@ public class GitRebaseEditor extends DialogWrapper {
return "reference.VersionControl.Git.RebaseCommits";
}
/**
* Cancel rebase
*
* @throws IOException if file cannot be reset to empty one
*/
public void cancel() throws IOException {
myTableModel.cancel(myFile);
@NotNull
public List<GitRebaseEntry> getEntries() {
return myTableModel.myEntries;
}
@@ -274,12 +242,13 @@ public class GitRebaseEditor extends DialogWrapper {
*/
private static final int SUBJECT = 2;
/**
* The entries
*/
final List<GitRebaseEntry> myEntries = new ArrayList<GitRebaseEntry>();
@NotNull private final List<GitRebaseEntry> myEntries;
private int[] myLastEditableSelectedRows = new int[]{};
MyTableModel(@NotNull List<GitRebaseEntry> entries) {
myEntries = entries;
}
/**
* {@inheritDoc}
*/
@@ -357,7 +326,7 @@ public class GitRebaseEditor extends DialogWrapper {
}
private void setSelection(ContiguousIntIntervalTracker intervalBuilder) {
myCommitsTable.getSelectionModel().setSelectionInterval( intervalBuilder.getMin() , intervalBuilder.getMax() );
myCommitsTable.getSelectionModel().setSelectionInterval(intervalBuilder.getMin(), intervalBuilder.getMax());
}
private void setRowAction(Object aValue, int rowIndex, int columnIndex) {
@@ -375,66 +344,6 @@ public class GitRebaseEditor extends DialogWrapper {
return columnIndex == ACTION;
}
/**
* Load data from the file
*
* @param file the file to load
* @throws IOException if file could not be loaded
*/
public void load(final String file) throws IOException {
String encoding = GitConfigUtil.getLogEncoding(myProject, myGitRoot);
final StringScanner s = new StringScanner(FileUtil.loadFile(new File(file), encoding));
while (s.hasMoreData()) {
if (s.isEol() || s.startsWith('#') || s.startsWith("noop")) {
s.nextLine();
continue;
}
String action = s.spaceToken();
String hash = s.spaceToken();
String comment = s.line();
myEntries.add(new GitRebaseEntry(action, hash, comment));
}
}
/**
* Save text to the file
*
* @param file the file to save to
* @throws IOException if there is IO problem
*/
public void save(final String file) throws IOException {
String encoding = GitConfigUtil.getLogEncoding(myProject, myGitRoot);
PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), encoding));
try {
for (GitRebaseEntry e : myEntries) {
if (e.getAction() != GitRebaseEntry.Action.skip) {
out.println(e.getAction().toString() + " " + e.getCommit() + " " + e.getSubject());
}
}
}
finally {
out.close();
}
}
/**
* Save text to the file
*
* @param file the file to save to
* @throws IOException if there is IO problem
*/
public void cancel(final String file) throws IOException {
PrintWriter out = new PrintWriter(new FileWriter(file));
try {
//noinspection HardCodedStringLiteral
out.println("# rebase is cancelled");
}
finally {
out.close();
}
}
public void moveRows(int[] rows, MoveDirection direction) {
myCommitsTable.removeEditor();
@@ -20,9 +20,11 @@ import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.ui.RawCommandLineEditor;
import com.intellij.ui.components.JBCheckBox;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.incremental.groovy.GreclipseSettings;
@@ -65,21 +67,26 @@ public class GreclipseConfigurable implements Configurable {
@Override
public boolean isModified() {
return !Comparing.equal(myJarPath.getText(), mySettings.greclipsePath) ||
return !Comparing.equal(getExternalizableJarPath(), mySettings.greclipsePath) ||
!Comparing.equal(myCmdLineParams.getText(), mySettings.cmdLineParams) ||
!Comparing.equal(myGenerateDebugInfo.isSelected(), mySettings.debugInfo);
}
@Override
public void apply() throws ConfigurationException {
mySettings.greclipsePath = myJarPath.getText();
mySettings.greclipsePath = getExternalizableJarPath();
mySettings.cmdLineParams = myCmdLineParams.getText();
mySettings.debugInfo = myGenerateDebugInfo.isSelected();
}
@NotNull
private String getExternalizableJarPath() {
return FileUtil.toSystemIndependentName(myJarPath.getText());
}
@Override
public void reset() {
myJarPath.setText(mySettings.greclipsePath);
myJarPath.setText(FileUtil.toSystemDependentName(mySettings.greclipsePath));
myCmdLineParams.setText(mySettings.cmdLineParams);
myGenerateDebugInfo.setSelected(mySettings.debugInfo);
}
+1 -1
View File
@@ -70,7 +70,7 @@
<reference ref="Annotate"/>
<separator/>
<action id="hg4idea.pull" class="org.zmlx.hg4idea.action.HgPullAction"/>
<action id="hg4idea.pull" class="org.zmlx.hg4idea.action.HgPullAction" icon="AllIcons.Actions.CheckOut"/>
<reference ref="Vcs.Push"/>
<separator/>
<action id="hg4idea.run.conflict.resolver" class="org.zmlx.hg4idea.action.HgRunConflictResolverAction"/>
@@ -12,10 +12,10 @@
// limitations under the License.
package org.zmlx.hg4idea.action;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vfs.VirtualFile;
@@ -25,19 +25,12 @@ import org.zmlx.hg4idea.repo.HgRepository;
import org.zmlx.hg4idea.repo.HgRepositoryManager;
import org.zmlx.hg4idea.util.HgUtil;
import javax.swing.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public abstract class HgAbstractGlobalAction extends AnAction {
protected HgAbstractGlobalAction(Icon icon) {
super(icon);
}
protected HgAbstractGlobalAction() {
}
public abstract class HgAbstractGlobalAction extends DumbAwareAction {
public void actionPerformed(@NotNull AnActionEvent event) {
final DataContext dataContext = event.getDataContext();
@@ -82,5 +75,4 @@ public abstract class HgAbstractGlobalAction extends AnAction {
}
return true;
}
}
@@ -20,20 +20,11 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.repo.HgRepository;
import javax.swing.*;
import java.util.Collection;
import java.util.List;
public abstract class HgAbstractGlobalSingleRepoAction extends HgAbstractGlobalAction {
public HgAbstractGlobalSingleRepoAction(Icon icon) {
super(icon);
}
public HgAbstractGlobalSingleRepoAction() {
super();
}
@Override
protected void execute(@NotNull Project project,
@NotNull Collection<HgRepository> repositories,
@@ -12,7 +12,6 @@
// limitations under the License.
package org.zmlx.hg4idea.action;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
@@ -26,9 +25,6 @@ import org.zmlx.hg4idea.util.HgErrorUtil;
import java.util.Collection;
public class HgPullAction extends HgAbstractGlobalSingleRepoAction {
public HgPullAction() {
super(AllIcons.Actions.CheckOut);
}
@Override
protected void execute(@NotNull final Project project, @NotNull Collection<HgRepository> repos, @Nullable HgRepository selectedRepo) {
@@ -16,12 +16,6 @@ import com.intellij.dvcs.DvcsUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Couple;
@@ -38,9 +32,6 @@ import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.impl.status.StatusBarUtil;
import com.intellij.ui.GuiUtils;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
@@ -284,36 +275,9 @@ public abstract class HgUtil {
return getHgRootOrThrow(project, VcsUtil.getFilePath(file.getPath()));
}
/**
* Returns the currently selected file, based on which HgBranch components will identify the current repository root.
*/
@Nullable
public static VirtualFile getSelectedFile(@NotNull Project project) {
StatusBar statusBar = WindowManager.getInstance().getStatusBar(project);
final FileEditor fileEditor = StatusBarUtil.getCurrentFileEditor(project, statusBar);
VirtualFile result = null;
if (fileEditor != null) {
if (fileEditor instanceof TextEditor) {
Document document = ((TextEditor)fileEditor).getEditor().getDocument();
result = FileDocumentManager.getInstance().getFile(document);
}
}
if (result == null) {
final FileEditorManager manager = FileEditorManager.getInstance(project);
if (manager != null) {
Editor editor = manager.getSelectedTextEditor();
if (editor != null) {
result = FileDocumentManager.getInstance().getFile(editor.getDocument());
}
}
}
return result;
}
@Nullable
public static VirtualFile getRootForSelectedFile(@NotNull Project project) {
VirtualFile selectedFile = getSelectedFile(project);
VirtualFile selectedFile = DvcsUtil.getSelectedFile(project);
if (selectedFile != null) {
return getHgRootOrNull(project, selectedFile);
}
@@ -17,10 +17,7 @@
package com.intellij.execution.junit;
import com.intellij.execution.*;
import com.intellij.execution.configurations.JavaParameters;
import com.intellij.execution.configurations.ParametersList;
import com.intellij.execution.configurations.RunnerSettings;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.configurations.*;
import com.intellij.execution.junit2.TestProxy;
import com.intellij.execution.junit2.segments.DeferredActionsQueue;
import com.intellij.execution.junit2.segments.DeferredActionsQueueImpl;
@@ -33,8 +30,7 @@ import com.intellij.execution.junit2.ui.model.CompletionEvent;
import com.intellij.execution.junit2.ui.model.JUnitRunningModel;
import com.intellij.execution.junit2.ui.model.RootTestInfo;
import com.intellij.execution.junit2.ui.properties.JUnitConsoleProperties;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.*;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.*;
@@ -173,7 +169,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
if (executionResult != null) {
return executionResult;
}
final JUnitProcessHandler handler = createHandler(executor);
final JUnitProcessHandler handler = createJUnitHandler(executor);
final RunnerSettings runnerSettings = getRunnerSettings();
JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(getConfiguration(), handler, runnerSettings);
final TestProxy unboundOutputRoot = new TestProxy(new RootTestInfo());
@@ -284,7 +280,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
}
@NotNull
protected JUnitProcessHandler createHandler(Executor executor) throws ExecutionException {
protected JUnitProcessHandler createJUnitHandler(Executor executor) throws ExecutionException {
appendForkInfo(executor);
final String repeatMode = getConfiguration().getRepeatMode();
if (!RepeatCount.ONCE.equals(repeatMode)) {
@@ -297,6 +293,27 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
return JUnitProcessHandler.runCommandLine(createCommandLine());
}
@NotNull
protected OSProcessHandler createHandler(Executor executor) throws ExecutionException {
appendForkInfo(executor);
final String repeatMode = getConfiguration().getRepeatMode();
if (!RepeatCount.ONCE.equals(repeatMode)) {
final int repeatCount = getConfiguration().getRepeatCount();
final String countString = RepeatCount.N.equals(repeatMode) && repeatCount > 0
? RepeatCount.getCountString(repeatCount)
: repeatMode;
getJavaParameters().getProgramParametersList().add(countString);
}
final OSProcessHandler processHandler = new KillableColoredProcessHandler(createCommandLine());
ProcessTerminatedListener.attach(processHandler);
final SearchForTestsTask searchForTestsTask = createSearchingForTestsTask();
if (searchForTestsTask != null) {
searchForTestsTask.attachTaskToProcess(processHandler);
}
return processHandler;
}
@NotNull
@Override
protected SMTRunnerConsoleProperties createTestConsoleProperties(Executor executor) {
@@ -60,8 +60,8 @@ public class TestPackage extends TestObject {
@NotNull
@Override
protected JUnitProcessHandler createHandler(Executor executor) throws ExecutionException {
final JUnitProcessHandler handler = super.createHandler(executor);
protected JUnitProcessHandler createJUnitHandler(Executor executor) throws ExecutionException {
final JUnitProcessHandler handler = super.createJUnitHandler(executor);
createSearchingForTestsTask().attachTaskToProcess(handler);
return handler;
}
@@ -18,6 +18,7 @@ package org.jetbrains.jps.maven.compiler;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Base64;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.storage.BuildDataPaths;
@@ -58,7 +59,7 @@ public class MavenCommonArtifactRootCopyingHandlerProvider extends ArtifactRootC
projectConfiguration.moduleConfigurations.get(getModuleName(artifact.getName()));
if (moduleResourceConfiguration != null && moduleResourceConfiguration.manifest != null) {
try {
FileUtil.writeToFile(root, moduleResourceConfiguration.manifest);
FileUtil.writeToFile(root, Base64.decode(moduleResourceConfiguration.manifest));
}
catch (IOException e) {
LOG.debug(e);
@@ -14,15 +14,20 @@ import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.StreamUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Base64;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.XmlSerializer;
import org.jdom.Document;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.dom.MavenDomUtil;
import org.jetbrains.idea.maven.dom.MavenPropertyResolver;
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel;
import org.jetbrains.idea.maven.dom.references.MavenFilteredPropertyPsiReferenceProvider;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.model.MavenResource;
@@ -222,8 +227,9 @@ public class MavenResourceCompilerConfigurationGenerator {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
manifest.write(outputStream);
resourceConfig.manifest = outputStream.toString("UTF8");
MavenDomProjectModel domModel = MavenDomUtil.getMavenDomProjectModel(module.getProject(), mavenProject.getFile());
final String resolvedText = MavenPropertyResolver.resolve(outputStream.toString(CharsetToolkit.UTF8), domModel);
resourceConfig.manifest = Base64.encode(resolvedText.getBytes(CharsetToolkit.UTF8));
}
finally {
StreamUtil.closeStream(outputStream);
@@ -23,7 +23,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
@@ -53,7 +53,7 @@ public abstract class TaskRepositoryType<T extends TaskRepository> implements Ta
public abstract TaskRepositoryEditor createEditor(T repository, Project project, Consumer<T> changeListener);
public List<TaskRepositorySubtype> getAvailableSubtypes() {
return Arrays.asList((TaskRepositorySubtype)this);
return Collections.singletonList((TaskRepositorySubtype)this);
}
@NotNull
@@ -15,49 +15,21 @@
*/
package com.intellij.tasks.jira.jql;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Constructor;
/**
* @author Mikhail Golubev
*/
public class JqlElementType extends IElementType {
private static final Class<?>[] PARAMETER_TYPES = {ASTNode.class};
private final Class<? extends PsiElement> myClass;
private Constructor<? extends PsiElement> myConstructor;
public JqlElementType(@NotNull @NonNls String debugName) {
this(debugName, ASTWrapperPsiElement.class);
}
public JqlElementType(@NotNull @NonNls String debugName, @NotNull Class<? extends PsiElement> cls) {
super(debugName, JqlLanguage.INSTANCE);
myClass = cls;
}
@Override
public String toString() {
return "JQL: " + super.toString();
}
@NotNull
public PsiElement createElement(@NotNull ASTNode node) {
try {
if (myConstructor == null) {
myConstructor = myClass.getConstructor(PARAMETER_TYPES);
}
return myConstructor.newInstance(node);
}
catch (Exception e) {
throw new AssertionError(
String.format("Class %s must have constructor accepting single ASTNode parameter", myClass.getName()));
}
}
}
@@ -1,9 +1,13 @@
package com.intellij.tasks.jira.jql;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.tasks.jira.jql.psi.impl.*;
import org.jetbrains.annotations.NotNull;
/**
* @author Mikhail Golubev
@@ -69,30 +73,89 @@ import com.intellij.tasks.jira.jql.psi.impl.*;
*/
public interface JqlElementTypes {
IFileElementType FILE = new IFileElementType(JqlLanguage.INSTANCE);
IElementType QUERY = new JqlElementType("QUERY", JqlQueryImpl.class);
IElementType OR_CLAUSE = new JqlElementType("OR_CLAUSE", JqlOrClauseImpl.class);
IElementType AND_CLAUSE = new JqlElementType("AND_CLAUSE", JqlAndClauseImpl.class);
IElementType NOT_CLAUSE = new JqlElementType("NOT_CLAUSE", JqlNotClauseImpl.class);
IElementType QUERY = new JqlElementType("QUERY");
IElementType OR_CLAUSE = new JqlElementType("OR_CLAUSE");
IElementType AND_CLAUSE = new JqlElementType("AND_CLAUSE");
IElementType NOT_CLAUSE = new JqlElementType("NOT_CLAUSE");
// actually parenthesized clause, named so to be consistent with official grammar
IElementType SUB_CLAUSE = new JqlElementType("SUB_CLAUSE", JqlSubClauseImpl.class);
IElementType SUB_CLAUSE = new JqlElementType("SUB_CLAUSE");
//IElementType TERMINAL_CLAUSE = new JqlElementType("TERMINAL_CLAUSE");
// field (= | != | ~ | !~ | < | > | <= | >= | is [not] | [not] in) value
IElementType SIMPLE_CLAUSE = new JqlElementType("SIMPLE_CLAUSE", JqlSimpleClauseImpl.class);
IElementType SIMPLE_CLAUSE = new JqlElementType("SIMPLE_CLAUSE");
// field was [not] [in] value {history_predicate}
IElementType WAS_CLAUSE = new JqlElementType("WAS_CLAUSE", JqlWasClauseImpl.class);
IElementType WAS_CLAUSE = new JqlElementType("WAS_CLAUSE");
// field changed {history_predicate}
IElementType CHANGED_CLAUSE = new JqlElementType("CHANGED_CLAUSE", JqlChangedClauseImpl.class);
IElementType LIST = new JqlElementType("LIST", JqlListImpl.class);
IElementType ORDER_BY = new JqlElementType("ORDER_BY", JqlOrderByImpl.class);
IElementType IDENTIFIER = new JqlElementType("IDENTIFIER", JqlIdentifierImpl.class);
IElementType LITERAL = new JqlElementType("LITERAL", JqlLiteralImpl.class);
IElementType FUNCTION_CALL = new JqlElementType("FUNCTION_CALL", JqlFunctionCallImpl.class);
IElementType ARGUMENT_LIST = new JqlElementType("ARGUMENT_LIST", JqlArgumentListImpl.class);
IElementType SORT_KEY = new JqlElementType("SORT_KEY", JqlSortKeyImpl.class);
IElementType EMPTY = new JqlElementType("EMPTY", JqlEmptyValueImpl.class);
IElementType HISTORY_PREDICATE = new JqlElementType("HISTORY_PREDICATE", JqlHistoryPredicateImpl.class);
IElementType CHANGED_CLAUSE = new JqlElementType("CHANGED_CLAUSE");
IElementType LIST = new JqlElementType("LIST");
IElementType ORDER_BY = new JqlElementType("ORDER_BY");
IElementType IDENTIFIER = new JqlElementType("IDENTIFIER");
IElementType LITERAL = new JqlElementType("LITERAL");
IElementType FUNCTION_CALL = new JqlElementType("FUNCTION_CALL");
IElementType ARGUMENT_LIST = new JqlElementType("ARGUMENT_LIST");
IElementType SORT_KEY = new JqlElementType("SORT_KEY");
IElementType EMPTY = new JqlElementType("EMPTY");
IElementType HISTORY_PREDICATE = new JqlElementType("HISTORY_PREDICATE");
TokenSet OPERAND_NODES = TokenSet.create(
JqlTokenTypes.NUMBER_LITERAL, JqlTokenTypes.STRING_LITERAL, LIST, FUNCTION_CALL, EMPTY
);
class Factory {
@NotNull
public static PsiElement createElement(@NotNull ASTNode node) {
final IElementType type = node.getElementType();
if (type == QUERY) {
return new JqlQueryImpl(node);
}
else if (type == OR_CLAUSE) {
return new JqlOrClauseImpl(node);
}
else if (type == AND_CLAUSE) {
return new JqlAndClauseImpl(node);
}
else if (type == NOT_CLAUSE) {
return new JqlNotClauseImpl(node);
}
else if (type == SUB_CLAUSE) {
return new JqlSubClauseImpl(node);
}
else if (type == SIMPLE_CLAUSE) {
return new JqlSimpleClauseImpl(node);
}
else if (type == WAS_CLAUSE) {
return new JqlWasClauseImpl(node);
}
else if (type == CHANGED_CLAUSE) {
return new JqlChangedClauseImpl(node);
}
else if (type == LIST) {
return new JqlListImpl(node);
}
else if (type == ORDER_BY) {
return new JqlOrderByImpl(node);
}
else if (type == IDENTIFIER) {
return new JqlIdentifierImpl(node);
}
else if (type == LITERAL) {
return new JqlLiteralImpl(node);
}
else if (type == FUNCTION_CALL) {
return new JqlFunctionCallImpl(node);
}
else if (type == ARGUMENT_LIST) {
return new JqlArgumentListImpl(node);
}
else if (type == SORT_KEY) {
return new JqlSortKeyImpl(node);
}
else if (type == EMPTY) {
return new JqlEmptyValueImpl(node);
}
else if (type == HISTORY_PREDICATE) {
return new JqlHistoryPredicateImpl(node);
}
return new ASTWrapperPsiElement(node);
}
}
}
@@ -1,6 +1,5 @@
package com.intellij.tasks.jira.jql;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.lang.ParserDefinition;
import com.intellij.lang.PsiParser;
@@ -10,7 +9,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
@@ -58,11 +56,7 @@ public class JqlParserDefinition implements ParserDefinition {
@NotNull
@Override
public PsiElement createElement(ASTNode node) {
final IElementType type = node.getElementType();
if (type instanceof JqlElementType) {
return ((JqlElementType)type).createElement(node);
}
return new ASTWrapperPsiElement(node);
return JqlElementTypes.Factory.createElement(node);
}
@Override
@@ -20,40 +20,31 @@
*/
package com.theoryinpractice.testng.configuration;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.execution.CantRunException;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.testframework.SearchForTestsTask;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PackageScope;
import com.intellij.psi.search.searches.AnnotatedMembersSearch;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.util.ClassUtil;
import com.theoryinpractice.testng.model.IDEARemoteTestRunnerClient;
import com.theoryinpractice.testng.model.TestClassFilter;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import com.theoryinpractice.testng.model.TestType;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.testng.xml.*;
import java.io.*;
import java.net.ServerSocket;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class SearchingForTestsTask extends SearchForTestsTask {
private static final Logger LOG = Logger.getInstance("#" + SearchingForTestsTask.class.getName());
@@ -233,14 +224,12 @@ public class SearchingForTestsTask extends SearchForTestsTask {
}
private boolean shouldSearchForTestMethods() {
boolean dependantMethods = false;
for (Map<PsiMethod, List<String>> methods : myClasses.values()) {
if (!methods.isEmpty()) {
dependantMethods = true;
break;
return true;
}
}
return dependantMethods;
return false;
}
private void composeTestSuiteFromXml() throws CantRunException {
@@ -280,182 +269,9 @@ public class SearchingForTestsTask extends SearchForTestsTask {
protected void fillTestObjects(final Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
final PsiManager psiManager = PsiManager.getInstance(myProject);
if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
final String packageName = data.getPackageName();
PsiPackage psiPackage = ApplicationManager.getApplication().runReadAction(
new Computable<PsiPackage>() {
@Nullable
public PsiPackage compute() {
return JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(packageName);
}
}
);
if (psiPackage == null) {
throw CantRunException.packageNotFound(packageName);
}
else {
TestSearchScope scope = myConfig.getPersistantData().getScope();
//TODO we should narrow this down by module really, if that's what's specified
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true);
TestClassFilter filter = projectFilter.intersectionWith(PackageScope.packageScope(psiPackage, true));
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(filter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in the package \"" + packageName + '\"');
}
}
}
else if (data.TEST_OBJECT.equals(TestType.CLASS.getType())) {
//it's a class
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(psiManager, data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
})) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
calculateDependencies(null, classes, psiClass);
}
else if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
//it's a method
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(psiManager, data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(
new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
}
)) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
collectTestMethods(classes, psiClass, data.getMethodName());
}
else if (data.TEST_OBJECT.equals(TestType.GROUP.getType())) {
//for a group, we include all classes
PsiClass[] testClasses = TestNGUtil
.getAllTestClasses(new TestClassFilter(data.getScope().getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true), false);
if (testClasses != null) {
for (PsiClass c : testClasses) {
classes.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
}
}
else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
for (final String pattern : data.getPatterns()) {
final String className;
final String methodName;
if (pattern.contains(",")) {
methodName = StringUtil.getShortName(pattern, ',');
className = StringUtil.getPackageName(pattern, ',');
} else {
className = pattern;
methodName = null;
}
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Nullable
@Override
public PsiClass compute() {
return ClassUtil.findPsiClass(psiManager, className.replace('/', '.'), null, true, getSearchScope());
}
});
if (psiClass != null) {
final Boolean hasTest = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return TestNGUtil.hasTest(psiClass);
}
});
if (hasTest) {
if (StringUtil.isEmpty(methodName)) {
calculateDependencies(null, classes, psiClass);
}
else {
collectTestMethods(classes, psiClass, methodName);
}
} else {
throw new CantRunException("No tests found in class " + className);
}
}
}
if (classes.size() != data.getPatterns().size()) {
TestSearchScope scope = myConfig.getPersistantData().getScope();
final List<Pattern> compilePatterns = new ArrayList<Pattern>();
for (String p : data.getPatterns()) {
final Pattern compilePattern;
try {
compilePattern = Pattern.compile(p);
}
catch (PatternSyntaxException e) {
continue;
}
if (compilePattern != null) {
compilePatterns.add(compilePattern);
}
}
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true){
@Override
public boolean isAccepted(PsiClass psiClass) {
if (super.isAccepted(psiClass)) {
final String qualifiedName = psiClass.getQualifiedName();
LOG.assertTrue(qualifiedName != null);
for (Pattern pattern : compilePatterns) {
if (pattern.matcher(qualifiedName).matches()) return true;
}
}
return false;
}
};
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(projectFilter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in for patterns \"" + StringUtil.join(data.getPatterns(), " || ") + '\"');
}
}
}
}
private void collectTestMethods(Map<PsiClass, Map<PsiMethod, List<String>>> classes, final PsiClass psiClass, final String methodName) {
final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(
new Computable<PsiMethod[]>() {
public PsiMethod[] compute() {
return psiClass.findMethodsByName(methodName, true);
}
}
);
calculateDependencies(methods, classes, psiClass);
Map<PsiMethod, List<String>> psiMethods = classes.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
classes.put(psiClass, psiMethods);
}
for (PsiMethod method : methods) {
psiMethods.put(method, Collections.<String>emptyList());
final TestNGTestObject testObject = TestNGTestObject.fromConfig(myConfig);
if (testObject != null) {
testObject.fillTestObjects(classes);
}
}
@@ -463,24 +279,15 @@ public class SearchingForTestsTask extends SearchForTestsTask {
Map<String, String> testParams = new HashMap<String, String>();
// Override with those from the test runner configuration
testParams.putAll(convertPropertiesFileToMap(myData.PROPERTIES_FILE));
testParams.putAll(myData.TEST_PROPERTIES);
return testParams;
}
private static Map<String, String> convertPropertiesFileToMap(String properties_file) {
Map<String, String> params = new HashMap<String, String>();
if (properties_file != null) {
File propertiesFile = new File(properties_file);
if (myData.PROPERTIES_FILE != null) {
File propertiesFile = new File(myData.PROPERTIES_FILE);
if (propertiesFile.exists()) {
Properties properties = new Properties();
try {
properties.load(new FileInputStream(propertiesFile));
for (Map.Entry entry : properties.entrySet()) {
params.put((String)entry.getKey(), (String)entry.getValue());
testParams.put((String)entry.getKey(), (String)entry.getValue());
}
}
@@ -489,155 +296,7 @@ public class SearchingForTestsTask extends SearchForTestsTask {
}
}
}
return params;
testParams.putAll(myData.TEST_PROPERTIES);
return testParams;
}
private void calculateDependencies(PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
@Nullable final PsiClass... classes) {
calculateDependencies(methods, results, new LinkedHashSet<PsiMember>(), classes);
}
private void calculateDependencies(final PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
@Nullable final PsiClass... classes) {
if (classes != null && classes.length > 0) {
final Set<String> groupDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(groupDependencies, "dependsOnGroups", methods, classes);
final Set<PsiMember> membersToCheckNow = new LinkedHashSet<PsiMember>();
if (!groupDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = classes[0].getProject();
final PsiClass testAnnotation =
JavaPsiFacade.getInstance(project).findClass(TestNGUtil.TEST_ANNOTATION_FQN, GlobalSearchScope.allScope(project));
LOG.assertTrue(testAnnotation != null);
for (PsiMember psiMember : AnnotatedMembersSearch.search(testAnnotation, getSearchScope())) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(psiMember, TestNGUtil.TEST_ANNOTATION_FQN);
if (TestNGUtil.isAnnotatedWithParameter(annotation, "groups", groupDependencies)) {
if (appendMember(psiMember, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(psiMember);
}
}
}
}
});
}
collectDependsOnMethods(results, alreadyMarkedToBeChecked, membersToCheckNow, methods, classes);
if (methods == null) {
for (PsiClass c : classes) {
results.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
} else {
for (PsiMember psiMember : membersToCheckNow) {
PsiClass psiClass;
PsiMethod[] meths = null;
if (psiMember instanceof PsiMethod) {
psiClass = psiMember.getContainingClass();
meths = new PsiMethod[] {(PsiMethod)psiMember};
} else {
psiClass = (PsiClass)psiMember;
}
calculateDependencies(meths, results, alreadyMarkedToBeChecked, psiClass);
}
}
}
}
private static void collectDependsOnMethods(final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
final Set<PsiMember> membersToCheckNow,
final PsiMethod[] methods,
final PsiClass... classes) {
final PsiClass[] psiClasses;
if (methods != null && methods.length > 0) {
final Set<PsiClass> containingClasses = new LinkedHashSet<PsiClass>();
for (final PsiMethod method : methods) {
containingClasses.add(ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Override
public PsiClass compute() {
return method.getContainingClass();
}
}));
}
psiClasses = containingClasses.toArray(new PsiClass[containingClasses.size()]);
} else {
psiClasses = classes;
}
for (final PsiClass containingClass : psiClasses) {
final Set<String> testMethodDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(testMethodDependencies, "dependsOnMethods", methods, containingClass);
if (!testMethodDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = containingClass.getProject();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
for (String dependency : testMethodDependencies) {
final String className = StringUtil.getPackageName(dependency);
final String methodName = StringUtil.getShortName(dependency);
if (StringUtil.isEmpty(className)) {
checkClassMethods(methodName, containingClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
else {
final PsiClass aClass = psiFacade.findClass(className, containingClass.getResolveScope());
if (aClass != null) {
checkClassMethods(methodName, aClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
}
}
}
});
}
}
}
private static void checkClassMethods(String methodName,
PsiClass containingClass,
Set<PsiMember> alreadyMarkedToBeChecked,
Set<PsiMember> membersToCheckNow,
Map<PsiClass, Map<PsiMethod, List<String>>> results) {
final PsiMethod[] psiMethods = containingClass.findMethodsByName(methodName, true);
for (PsiMethod method : psiMethods) {
if (AnnotationUtil.isAnnotated(method, TestNGUtil.TEST_ANNOTATION_FQN, false) &&
appendMember(method, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(method);
}
}
}
private static boolean appendMember(final PsiMember psiMember,
final Set<PsiMember> underConsideration,
final Map<PsiClass, Map<PsiMethod, List<String>>> results) {
boolean result = false;
final PsiClass psiClass = psiMember instanceof PsiClass ? ((PsiClass)psiMember) : psiMember.getContainingClass();
Map<PsiMethod, List<String>> psiMethods = results.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
results.put(psiClass, psiMethods);
if (psiMember instanceof PsiClass) {
result = underConsideration.add(psiMember);
}
}
if (psiMember instanceof PsiMethod) {
final boolean add = psiMethods.put((PsiMethod)psiMember, Collections.<String>emptyList()) != null;
if (add) {
return underConsideration.add(psiMember);
}
return false;
}
return result;
}
@NotNull
private GlobalSearchScope getSearchScope() {
final TestData data = myConfig.getPersistantData();
final Module module = myConfig.getConfigurationModule().getModule();
return data.TEST_OBJECT.equals(TestType.PACKAGE.getType())
? myConfig.getPersistantData().getScope().getSourceScope(myConfig).getGlobalSearchScope()
: module != null ? GlobalSearchScope.moduleWithDependenciesScope(module) : GlobalSearchScope.projectScope(myConfig.getProject());
}
}
@@ -29,7 +29,6 @@ import com.intellij.execution.configuration.EnvironmentVariablesComponent;
import com.intellij.execution.configurations.*;
import com.intellij.execution.junit.RefactoringListeners;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.execution.util.ProgramParametersUtil;
@@ -47,12 +46,12 @@ import com.intellij.refactoring.listeners.RefactoringElementAdapter;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.refactoring.listeners.UndoRefactoringElementListener;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import com.theoryinpractice.testng.model.TestType;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.testng.xml.Parser;
import java.util.*;
@@ -68,7 +67,7 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
public boolean ALTERNATIVE_JRE_PATH_ENABLED;
public String ALTERNATIVE_JRE_PATH;
private static final Object PARSE_LOCK = new Object();
public static final String DEFAULT_PACKAGE_NAME = ExecutionBundle.message("default.package.presentable.name");
public static final String DEFAULT_PACKAGE_CONFIGURATION_NAME = ExecutionBundle.message("default.package.configuration.name");
@@ -149,32 +148,14 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
@Override
public String suggestedName() {
return data.getGeneratedName(getConfigurationModule());
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
return testObject != null ? testObject.getGeneratedName() : null;
}
@Override
public String getActionName() {
if (TestType.CLASS.getType().equals(data.TEST_OBJECT)) {
String shortName = JavaExecutionUtil.getShortClassName(data.MAIN_CLASS_NAME);
return ProgramRunnerUtil.shortenName(shortName, 0);
}
if (TestType.PACKAGE.getType().equals(data.TEST_OBJECT)) {
String s = getName();
if (!isGeneratedName()) return '\"' + s + '\"';
if (data.getPackageName().trim().length() > 0) {
return "Tests in \"" + data.getPackageName() + '\"';
}
else {
return "All Tests";
}
}
if (TestType.METHOD.getType().equals(data.TEST_OBJECT)) {
return data.getMethodName() + "()";
}
if (TestType.SUITE.getType().equals(data.TEST_OBJECT)) {
return data.getSuiteName();
}
return data.getGroupName();
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
return testObject != null ? ProgramRunnerUtil.shortenName(testObject.getActionName(), 0) : null;
}
public void setVMParameters(String value) {
@@ -299,45 +280,9 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
if (data.TEST_OBJECT.equals(TestType.CLASS.getType()) || data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
final SourceScope scope = data.getScope().getSourceScope(this);
if (scope == null) {
throw new RuntimeConfigurationException("Invalid scope specified");
}
PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
PsiMethod[] methods = psiClass.findMethodsByName(data.getMethodName(), true);
if (methods.length == 0) {
throw new RuntimeConfigurationException("Method '" + data.getMethodName() + "' not found");
}
for (PsiMethod method : methods) {
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
throw new RuntimeConfigurationException("Non public method '" + data.getMethodName() + "'specified");
}
}
}
}
else if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
PsiPackage psiPackage = JavaPsiFacade.getInstance(project).findPackage(data.getPackageName());
if (psiPackage == null) throw new RuntimeConfigurationException("Package '" + data.getPackageName() + "' not found");
}
else if (data.TEST_OBJECT.equals(TestType.SUITE.getType())) {
try {
final Parser parser = new Parser(data.getSuiteName());
parser.setLoadClasses(false);
synchronized (PARSE_LOCK) {
parser.parse();//try to parse suite.xml
}
}
catch (Exception e) {
throw new RuntimeConfigurationException("Unable to parse '" + data.getSuiteName() + "' specified");
}
} else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
final Set<String> patterns = data.getPatterns();
if (patterns.isEmpty()) {
throw new RuntimeConfigurationWarning("No pattern selected");
}
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
if (testObject != null) {
testObject.checkConfiguration();
}
JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
ProgramParametersUtil.checkWorkingDirectoryExist(this, getProject(), getConfigurationModule().getModule());
@@ -33,6 +33,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiElement;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import org.testng.IDEATestNGRemoteListener;
public abstract class TestNGConfigurationProducer extends JavaRunConfigurationProducerBase<TestNGConfiguration> implements Cloneable {
@@ -58,7 +59,7 @@ public abstract class TestNGConfigurationProducer extends JavaRunConfigurationPr
String paramSetName = contextLocation instanceof PsiMemberParameterizedLocation
? getInvocationNumber(((PsiMemberParameterizedLocation)contextLocation).getParamSetName()) : null;
if (paramSetName != null && !Comparing.strEqual(paramSetName, testNGConfiguration.getProgramParameters())) return false;
TestData testobject = testNGConfiguration.getPersistantData();
TestNGTestObject testobject = TestNGTestObject.fromConfig(testNGConfiguration);
if (testobject != null) {
if (testobject.isConfiguredByElement(element)) {
final Module configurationModule = testNGConfiguration.getConfigurationModule().getModule();
@@ -33,6 +33,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiElement;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import icons.TestngIcons;
import org.jetbrains.annotations.NotNull;
@@ -72,7 +73,8 @@ public class TestNGConfigurationType implements ConfigurationType
return false;
else {
final PsiElement element = location.getPsiElement();
if (testobject.isConfiguredByElement(element)) {
final TestNGTestObject testNGTestObject = TestNGTestObject.fromConfig(config);
if (testNGTestObject != null && testNGTestObject.isConfiguredByElement(element)) {
final Module configurationModule = config.getConfigurationModule().getModule();
if (Comparing.equal(location.getModule(), configurationModule)) return true;
@@ -18,9 +18,7 @@ package com.theoryinpractice.testng.configuration;
import com.intellij.execution.*;
import com.intellij.execution.configurations.*;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.*;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.*;
@@ -76,10 +74,10 @@ public class TestNGRunnableState extends JavaTestFrameworkRunnableState<TestNGCo
@NotNull
@Override
protected OSProcessHandler startProcess() throws ExecutionException {
final OSProcessHandler handler = super.startProcess();
createSearchingForTestsTask().attachTaskToProcess(handler);
return handler;
final OSProcessHandler processHandler = new KillableColoredProcessHandler(createCommandLine());
ProcessTerminatedListener.attach(processHandler);
createSearchingForTestsTask().attachTaskToProcess(processHandler);
return processHandler;
}
@NotNull
@@ -18,16 +18,15 @@ package com.theoryinpractice.testng.model;
import com.intellij.execution.ExternalizablePath;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.Location;
import com.intellij.execution.configurations.JavaRunConfigurationModule;
import com.intellij.execution.junit.JUnitUtil;
import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiPackage;
import java.util.*;
@@ -174,26 +173,6 @@ public class TestData implements Cloneable
return data;
}
public String getGeneratedName(JavaRunConfigurationModule runconfigurationmodule) {
if (TestType.PACKAGE.getType().equals(TEST_OBJECT)) if (getPackageName().length() == 0) return "<default>";
else return getPackageName();
String name = JavaExecutionUtil.getPresentableClassName(getMainClassName());
if (TestType.METHOD.getType().equals(TEST_OBJECT)) {
return name + '.' + getMethodName();
}
else if (TestType.SUITE.getType().equals(TEST_OBJECT)) {
return getSuiteName();
}
else {
if (TestType.PATTERN.getType().equals(TEST_OBJECT)) {
final int size = myPatterns.size();
if (size == 0) return "Temp suite";
return StringUtil.getShortName(myPatterns.iterator().next()) + (size > 1 ? " and " + (size - 1) + " more" : "");
}
return name;
}
}
public String getMainClassName() {
return MAIN_CLASS_NAME == null ? "" : MAIN_CLASS_NAME;
}
@@ -217,28 +196,6 @@ public class TestData implements Cloneable
return JavaExecutionUtil.findModule(psiclass);
}
public boolean isConfiguredByElement(PsiElement element) {
if (TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
if (element instanceof PsiPackage) {
return Comparing.strEqual(PACKAGE_NAME, ((PsiPackage) element).getQualifiedName());
} else if (element instanceof PsiDirectory) {
final PsiPackage psiPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
return psiPackage != null && Comparing.strEqual(PACKAGE_NAME, psiPackage.getQualifiedName());
}
}
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
if (element instanceof PsiMethod && TEST_OBJECT.equals(TestType.METHOD.getType())) {
final PsiClass aClass = ((PsiMethod) element).getContainingClass();
return aClass != null &&
Comparing.strEqual(MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName(aClass)) &&
Comparing.strEqual(METHOD_NAME, ((PsiMethod) element).getName());
} else if (element instanceof PsiClass && TEST_OBJECT.equals(TestType.CLASS.getType())) {
return Comparing.strEqual(MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName((PsiClass) element));
}
return false;
}
public Map<String, String> getEnvs() {
return ENVS;
}
@@ -0,0 +1,95 @@
/*
* Copyright 2000-2015 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class TestNGTestClass extends TestNGTestObject {
public TestNGTestClass(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
//it's a class
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
})) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
calculateDependencies(null, classes, psiClass);
}
@Override
public String getGeneratedName() {
return JavaExecutionUtil.getPresentableClassName(myConfig.getPersistantData().getMainClassName());
}
@Override
public String getActionName() {
return JavaExecutionUtil.getShortClassName(myConfig.getPersistantData().MAIN_CLASS_NAME);
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
final SourceScope scope = data.getScope().getSourceScope(myConfig);
if (scope == null) {
throw new RuntimeConfigurationException("Invalid scope specified");
}
PsiClass psiClass = JavaPsiFacade.getInstance(myConfig.getProject()).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
}
@Override
public boolean isConfiguredByElement(PsiElement element) {
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
if (element instanceof PsiClass) {
return Comparing.strEqual(myConfig.getPersistantData().getMethodName(), JavaExecutionUtil.getRuntimeQualifiedName((PsiClass) element));
}
return false;
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2000-2015 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class TestNGTestGroup extends TestNGTestObject {
public TestNGTestGroup(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
//for a group, we include all classes
final TestClassFilter classFilter =
new TestClassFilter(data.getScope().getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true);
PsiClass[] testClasses = TestNGUtil.getAllTestClasses(classFilter, false);
if (testClasses != null) {
for (PsiClass c : testClasses) {
classes.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
}
}
@Override
public String getGeneratedName() {
return myConfig.getPersistantData().getGroupName();
}
@Override
public String getActionName() {
return myConfig.getPersistantData().getGroupName();
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
//check group exist?
}
}
@@ -0,0 +1,110 @@
/*
* Copyright 2000-2015 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class TestNGTestMethod extends TestNGTestObject {
public TestNGTestMethod(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(
new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
}
)) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
collectTestMethods(classes, psiClass, data.getMethodName());
}
@Override
public String getGeneratedName() {
final TestData data = myConfig.getPersistantData();
return JavaExecutionUtil.getPresentableClassName(data.getMainClassName()) + '.' + data.getMethodName();
}
@Override
public String getActionName() {
return myConfig.getPersistantData().getMethodName() + "()";
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
final SourceScope scope = data.getScope().getSourceScope(myConfig);
if (scope == null) {
throw new RuntimeConfigurationException("Invalid scope specified");
}
PsiClass psiClass = JavaPsiFacade.getInstance(myConfig.getProject()).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
PsiMethod[] methods = psiClass.findMethodsByName(data.getMethodName(), true);
if (methods.length == 0) {
throw new RuntimeConfigurationException("Method '" + data.getMethodName() + "' not found");
}
for (PsiMethod method : methods) {
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
throw new RuntimeConfigurationException("Non public method '" + data.getMethodName() + "'specified");
}
}
}
@Override
public boolean isConfiguredByElement(PsiElement element) {
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
if (element instanceof PsiMethod) {
final PsiClass aClass = ((PsiMethod) element).getContainingClass();
final TestData data = myConfig.getPersistantData();
return aClass != null &&
Comparing.strEqual(data.MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName(aClass)) &&
Comparing.strEqual(data.METHOD_NAME, ((PsiMethod) element).getName());
}
return false;
}
}
@@ -0,0 +1,247 @@
/*
* Copyright 2000-2015 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.theoryinpractice.testng.model;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.AnnotatedMembersSearch;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public abstract class TestNGTestObject {
private static final Logger LOG = Logger.getInstance("#" + TestNGTestObject.class.getName());
protected final TestNGConfiguration myConfig;
public TestNGTestObject(TestNGConfiguration config) {
myConfig = config;
}
public static TestNGTestObject fromConfig(TestNGConfiguration config) {
final TestData data = config.getPersistantData();
if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
return new TestNGTestPackage(config);
}
if (data.TEST_OBJECT.equals(TestType.CLASS.getType())) {
return new TestNGTestClass(config);
}
if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
return new TestNGTestMethod(config);
}
if (data.TEST_OBJECT.equals(TestType.GROUP.getType())) {
return new TestNGTestGroup(config);
}
if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
return new TestNGTestPattern(config);
}
if (data.TEST_OBJECT.equals(TestType.SUITE.getType())){
return new TestNGTestSuite(config);
}
assert false : data.TEST_OBJECT;
return null;
}
public abstract void fillTestObjects(final Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException;
public abstract String getGeneratedName();
public abstract String getActionName();
public abstract void checkConfiguration() throws RuntimeConfigurationException;
public boolean isConfiguredByElement(PsiElement element) {
return false;
}
protected void calculateDependencies(PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
@Nullable final PsiClass... classes) {
calculateDependencies(methods, results, new LinkedHashSet<PsiMember>(), classes);
}
private void calculateDependencies(final PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
@Nullable final PsiClass... classes) {
if (classes != null && classes.length > 0) {
final Set<String> groupDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(groupDependencies, "dependsOnGroups", methods, classes);
final Set<PsiMember> membersToCheckNow = new LinkedHashSet<PsiMember>();
if (!groupDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = classes[0].getProject();
final PsiClass testAnnotation =
JavaPsiFacade.getInstance(project).findClass(TestNGUtil.TEST_ANNOTATION_FQN, GlobalSearchScope.allScope(project));
LOG.assertTrue(testAnnotation != null);
for (PsiMember psiMember : AnnotatedMembersSearch.search(testAnnotation, getSearchScope())) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(psiMember, TestNGUtil.TEST_ANNOTATION_FQN);
if (TestNGUtil.isAnnotatedWithParameter(annotation, "groups", groupDependencies)) {
if (appendMember(psiMember, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(psiMember);
}
}
}
}
});
}
collectDependsOnMethods(results, alreadyMarkedToBeChecked, membersToCheckNow, methods, classes);
if (methods == null) {
for (PsiClass c : classes) {
results.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
} else {
for (PsiMember psiMember : membersToCheckNow) {
PsiClass psiClass;
PsiMethod[] meths = null;
if (psiMember instanceof PsiMethod) {
psiClass = psiMember.getContainingClass();
meths = new PsiMethod[] {(PsiMethod)psiMember};
} else {
psiClass = (PsiClass)psiMember;
}
calculateDependencies(meths, results, alreadyMarkedToBeChecked, psiClass);
}
}
}
}
private static void collectDependsOnMethods(final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
final Set<PsiMember> membersToCheckNow,
final PsiMethod[] methods,
final PsiClass... classes) {
final PsiClass[] psiClasses;
if (methods != null && methods.length > 0) {
final Set<PsiClass> containingClasses = new LinkedHashSet<PsiClass>();
for (final PsiMethod method : methods) {
containingClasses.add(ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Override
public PsiClass compute() {
return method.getContainingClass();
}
}));
}
psiClasses = containingClasses.toArray(new PsiClass[containingClasses.size()]);
} else {
psiClasses = classes;
}
for (final PsiClass containingClass : psiClasses) {
final Set<String> testMethodDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(testMethodDependencies, "dependsOnMethods", methods, containingClass);
if (!testMethodDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = containingClass.getProject();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
for (String dependency : testMethodDependencies) {
final String className = StringUtil.getPackageName(dependency);
final String methodName = StringUtil.getShortName(dependency);
if (StringUtil.isEmpty(className)) {
checkClassMethods(methodName, containingClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
else {
final PsiClass aClass = psiFacade.findClass(className, containingClass.getResolveScope());
if (aClass != null) {
checkClassMethods(methodName, aClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
}
}
}
});
}
}
}
private static void checkClassMethods(String methodName,
PsiClass containingClass,
Set<PsiMember> alreadyMarkedToBeChecked,
Set<PsiMember> membersToCheckNow,
Map<PsiClass, Map<PsiMethod, List<String>>> results) {
final PsiMethod[] psiMethods = containingClass.findMethodsByName(methodName, true);
for (PsiMethod method : psiMethods) {
if (AnnotationUtil.isAnnotated(method, TestNGUtil.TEST_ANNOTATION_FQN, false) &&
appendMember(method, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(method);
}
}
}
private static boolean appendMember(final PsiMember psiMember,
final Set<PsiMember> underConsideration,
final Map<PsiClass, Map<PsiMethod, List<String>>> results) {
boolean result = false;
final PsiClass psiClass = psiMember instanceof PsiClass ? ((PsiClass)psiMember) : psiMember.getContainingClass();
Map<PsiMethod, List<String>> psiMethods = results.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
results.put(psiClass, psiMethods);
if (psiMember instanceof PsiClass) {
result = underConsideration.add(psiMember);
}
}
if (psiMember instanceof PsiMethod) {
final boolean add = psiMethods.put((PsiMethod)psiMember, Collections.<String>emptyList()) != null;
if (add) {
return underConsideration.add(psiMember);
}
return false;
}
return result;
}
@NotNull
protected GlobalSearchScope getSearchScope() {
final TestData data = myConfig.getPersistantData();
final Module module = myConfig.getConfigurationModule().getModule();
return data.TEST_OBJECT.equals(TestType.PACKAGE.getType())
? myConfig.getPersistantData().getScope().getSourceScope(myConfig).getGlobalSearchScope()
: module != null ? GlobalSearchScope.moduleWithDependenciesScope(module) : GlobalSearchScope.projectScope(myConfig.getProject());
}
protected void collectTestMethods(Map<PsiClass, Map<PsiMethod, List<String>>> classes, final PsiClass psiClass, final String methodName) {
final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(
new Computable<PsiMethod[]>() {
public PsiMethod[] compute() {
return psiClass.findMethodsByName(methodName, true);
}
}
);
calculateDependencies(methods, classes, psiClass);
Map<PsiMethod, List<String>> psiMethods = classes.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
classes.put(psiClass, psiMethods);
}
for (PsiMethod method : methods) {
psiMethods.put(method, Collections.<String>emptyList());
}
}
}
@@ -0,0 +1,103 @@
/*
* Copyright 2000-2015 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.PackageScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class TestNGTestPackage extends TestNGTestObject {
public TestNGTestPackage(TestNGConfiguration configuration) {
super(configuration);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException {
final String packageName = myConfig.getPersistantData().getPackageName();
PsiPackage psiPackage = ApplicationManager.getApplication().runReadAction(
new Computable<PsiPackage>() {
@Nullable
public PsiPackage compute() {
return JavaPsiFacade.getInstance(myConfig.getProject()).findPackage(packageName);
}
}
);
if (psiPackage == null) {
throw CantRunException.packageNotFound(packageName);
}
else {
TestSearchScope scope = myConfig.getPersistantData().getScope();
//TODO we should narrow this down by module really, if that's what's specified
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true);
TestClassFilter filter = projectFilter.intersectionWith(PackageScope.packageScope(psiPackage, true));
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(filter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in the package \"" + packageName + '\"');
}
}
}
@Override
public String getGeneratedName() {
final String packageName = myConfig.getPersistantData().getPackageName();
return packageName.length() == 0 ? "<default>" : packageName;
}
@Override
public String getActionName() {
String s = myConfig.getName();
if (!myConfig.isGeneratedName()) return '\"' + s + '\"';
if (myConfig.getPersistantData().getPackageName().trim().length() > 0) {
return "Tests in \"" + myConfig.getPersistantData().getPackageName() + '\"';
}
else {
return "All Tests";
}
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
PsiPackage psiPackage = JavaPsiFacade.getInstance(myConfig.getProject()).findPackage(data.getPackageName());
if (psiPackage == null) throw new RuntimeConfigurationException("Package '" + data.getPackageName() + "' not found");
}
@Override
public boolean isConfiguredByElement(PsiElement element) {
final String packageName = myConfig.getPersistantData().getPackageName();
if (element instanceof PsiPackage) {
return Comparing.strEqual(packageName, ((PsiPackage)element).getQualifiedName());
} else if (element instanceof PsiDirectory) {
final PsiPackage psiPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
return psiPackage != null && Comparing.strEqual(packageName, psiPackage.getQualifiedName());
}
return false;
}
}
@@ -0,0 +1,145 @@
/*
* Copyright 2000-2015 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.configurations.RuntimeConfigurationWarning;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.util.ClassUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class TestNGTestPattern extends TestNGTestObject {
private static final Logger LOG = Logger.getInstance("#" + TestNGTestPattern.class.getName());
public TestNGTestPattern(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
for (final String pattern : data.getPatterns()) {
final String className;
final String methodName;
if (pattern.contains(",")) {
methodName = StringUtil.getShortName(pattern, ',');
className = StringUtil.getPackageName(pattern, ',');
} else {
className = pattern;
methodName = null;
}
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Nullable
@Override
public PsiClass compute() {
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), className.replace('/', '.'), null, true, getSearchScope());
}
});
if (psiClass != null) {
final Boolean hasTest = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return TestNGUtil.hasTest(psiClass);
}
});
if (hasTest) {
if (StringUtil.isEmpty(methodName)) {
calculateDependencies(null, classes, psiClass);
}
else {
collectTestMethods(classes, psiClass, methodName);
}
} else {
throw new CantRunException("No tests found in class " + className);
}
}
}
if (classes.size() != data.getPatterns().size()) {
TestSearchScope scope = myConfig.getPersistantData().getScope();
final List<Pattern> compilePatterns = new ArrayList<Pattern>();
for (String p : data.getPatterns()) {
final Pattern compilePattern;
try {
compilePattern = Pattern.compile(p);
}
catch (PatternSyntaxException e) {
continue;
}
if (compilePattern != null) {
compilePatterns.add(compilePattern);
}
}
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true){
@Override
public boolean isAccepted(PsiClass psiClass) {
if (super.isAccepted(psiClass)) {
final String qualifiedName = psiClass.getQualifiedName();
LOG.assertTrue(qualifiedName != null);
for (Pattern pattern : compilePatterns) {
if (pattern.matcher(qualifiedName).matches()) return true;
}
}
return false;
}
};
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(projectFilter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in for patterns \"" + StringUtil.join(data.getPatterns(), " || ") + '\"');
}
}
}
@Override
public String getGeneratedName() {
final Set<String> patterns = myConfig.getPersistantData().getPatterns();
final int size = patterns.size();
if (size == 0) return "Temp suite";
return StringUtil.getShortName(patterns.iterator().next()) + (size > 1 ? " and " + (size - 1) + " more" : "");
}
@Override
public String getActionName() {
return getGeneratedName();
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final Set<String> patterns = myConfig.getPersistantData().getPatterns();
if (patterns.isEmpty()) {
throw new RuntimeConfigurationWarning("No pattern selected");
}
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2000-2015 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import org.testng.xml.Parser;
import java.util.List;
import java.util.Map;
public class TestNGTestSuite extends TestNGTestObject {
private static final Object PARSE_LOCK = new Object();
public TestNGTestSuite(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException {}
@Override
public String getGeneratedName() {
return myConfig.getPersistantData().getSuiteName();
}
@Override
public String getActionName() {
return myConfig.getPersistantData().getSuiteName();
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
try {
final Parser parser = new Parser(data.getSuiteName());
parser.setLoadClasses(false);
synchronized (PARSE_LOCK) {
parser.parse();//try to parse suite.xml
}
}
catch (Exception e) {
throw new RuntimeConfigurationException("Unable to parse '" + data.getSuiteName() + "' specified");
}
}
}
@@ -436,7 +436,7 @@ public class TestNGUtil {
public void run() {
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
final Collection<PsiClass> set = new HashSet<PsiClass>();
final Collection<PsiClass> set = new LinkedHashSet<PsiClass>();
PsiManager manager = PsiManager.getInstance(filter.getProject());
GlobalSearchScope scope = filter.getScope();
GlobalSearchScope projectScope = GlobalSearchScope.projectScope(manager.getProject());
@@ -445,7 +445,9 @@ public class TestNGUtil {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
if (filter.isAccepted(psiClass)) {
indicator.setText2("Found test class " + psiClass.getQualifiedName());
if (indicator != null) {
indicator.setText2("Found test class " + psiClass.getQualifiedName());
}
set.add(psiClass);
}
}
@@ -0,0 +1,135 @@
/*
* Copyright 2000-2015 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.theoryinpractice.testng.configuration;
import com.intellij.execution.CantRunException;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import com.theoryinpractice.testng.model.TestType;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class DetectClassesToRunTest extends LightCodeInsightFixtureTestCase {
@BeforeMethod
@Override
protected void setUp() throws Exception {
super.setUp();
myFixture.addClass("package org.testng.annotations; @interface Test {public String[] dependsOnMethods() default {};}");
myFixture.addClass("package org.testng.annotations; @interface BeforeClass {}");
}
@AfterMethod
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
@Test
public void testNonRelatedBeforeClassIncluded() throws Exception {
final PsiClass configClass = myFixture.addClass("package p; public class AConfig {@org.testng.annotations.BeforeClass public void setup(){}}");
final PsiClass testClass = myFixture.addClass("package p; public class ATest {@org.testng.annotations.Test public void testOne(){}}");
//should not be included in resulted xml
myFixture.addClass("package p; public class BTest {}");
doTestPackageConfiguration(configClass, testClass);
}
@Test
public void testNonRelatedIncludedWhenConfigIsLocatedInSuperclassInAnotherPackage() throws Exception {
myFixture.addClass("package a; public class AConfig {@org.testng.annotations.BeforeClass public void setup(){}}");
final PsiClass emptyClassWithSuperConfig = myFixture.addClass("package p; import a.AConfig; public class BConfig extends AConfig {}");
final PsiClass testClass = myFixture.addClass("package p; public class ATest {@org.testng.annotations.Test public void testOne(){}}");
doTestPackageConfiguration(emptyClassWithSuperConfig, testClass);
}
@Test
public void testBeforeClassIsIncludedIfRunOnlyOneMethod() throws Exception {
final PsiClass aClass =
myFixture.addClass("package a; public class AConfig {" +
"@org.testng.annotations.BeforeClass public void setup(){}\n" +
"@org.testng.annotations.Test public void testOne(){}\n" +
"}");
doTestMethodConfiguration(aClass, aClass.getMethods()[1]);
}
@Test
public void testOneMethodWhenAnnotationIsOnBaseClassOnly() throws Exception {
myFixture.addClass("package a; @org.testng.annotations.Test public class BaseClass {}");
final PsiClass aClass =
myFixture.addClass("package a; public class ATest extends BaseClass {" +
" public void testOne(){}\n" +
"}");
doTestMethodConfiguration(aClass, aClass.getMethods());
}
@Test
public void testOneMethodWithDependencies() throws Exception {
final PsiClass aClass =
myFixture.addClass("package a; public class ATest {" +
" @org.testng.annotations.Test\n" +
" public void testTwo(){}\n " +
" @org.testng.annotations.Test(dependsOnMethods=\"testTwo\")\n" +
" public void testOne(){}\n" +
"}");
doTestMethodConfiguration(aClass, aClass.getMethods());
}
private void doTestMethodConfiguration(PsiClass aClass, PsiMethod... expectedMethods) throws CantRunException {
final TestNGConfiguration configuration =
new TestNGConfiguration("testOne", getProject(), TestNGConfigurationType.getInstance().getConfigurationFactories()[0]);
final TestData data = configuration.getPersistantData();
data.TEST_OBJECT = TestType.METHOD.getType();
data.METHOD_NAME = "testOne";
data.setScope(TestSearchScope.SINGLE_MODULE);
configuration.setModule(data.setMainClass(aClass));
final TestNGTestObject testObject = TestNGTestObject.fromConfig(configuration);
assertNotNull(testObject);
final LinkedHashMap<PsiClass, Map<PsiMethod, List<String>>> classes = new LinkedHashMap<PsiClass, Map<PsiMethod, List<String>>>();
testObject.fillTestObjects(classes);
assertContainsElements(classes.keySet(), aClass);
final Map<PsiMethod, List<String>> methods = classes.get(aClass);
assertContainsElements(methods.keySet(), expectedMethods);
}
private void doTestPackageConfiguration(PsiClass... containingClasses) throws CantRunException {
final TestNGConfiguration configuration =
new TestNGConfiguration("p", getProject(), TestNGConfigurationType.getInstance().getConfigurationFactories()[0]);
final TestData data = configuration.getPersistantData();
data.TEST_OBJECT = TestType.PACKAGE.getType();
data.PACKAGE_NAME = "p";
data.setScope(TestSearchScope.WHOLE_PROJECT);
final TestNGTestObject testObject = TestNGTestObject.fromConfig(configuration);
assertNotNull(testObject);
final LinkedHashMap<PsiClass, Map<PsiMethod, List<String>>> classes = new LinkedHashMap<PsiClass, Map<PsiMethod, List<String>>>();
testObject.fillTestObjects(classes);
assertContainsElements(classes.keySet(), containingClasses);
for (PsiClass psiClass : containingClasses) {
assertEmpty(classes.get(psiClass).keySet());
}
}
}
@@ -68,4 +68,9 @@ public final class HistoryElement implements Copyable<HistoryElement> {
public HistoryElement changeExpression(String expression) {
return new HistoryElement(expression, variables, namespaces);
}
@Override
public String toString() {
return expression;
}
}
@@ -20,6 +20,7 @@ import com.intellij.find.FindProgressIndicator;
import com.intellij.find.FindSettings;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -34,6 +35,7 @@ import org.intellij.plugins.xpathView.XPathEvalAction;
import org.intellij.plugins.xpathView.XPathProjectComponent;
import org.intellij.plugins.xpathView.support.XPathSupport;
import org.intellij.plugins.xpathView.ui.InputExpressionDialog;
import org.intellij.plugins.xpathView.util.Namespace;
import org.jaxen.JaxenException;
import org.jaxen.XPathSyntaxException;
import org.jetbrains.annotations.NotNull;
@@ -43,12 +45,12 @@ import java.util.Collections;
public class FindByXPathAction extends AnAction {
public void update(AnActionEvent e) {
final Project project = LangDataKeys.PROJECT.getData(e.getDataContext());
final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
e.getPresentation().setEnabled(project != null);
}
public void actionPerformed(AnActionEvent e) {
final Project project = LangDataKeys.PROJECT.getData(e.getDataContext());
final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
final Module module = LangDataKeys.MODULE.getData(e.getDataContext());
if (project != null) {
@@ -141,7 +143,7 @@ public class FindByXPathAction extends AnAction {
private static boolean validateExpression(Project project, String expression) {
try {
//noinspection unchecked
XPathSupport.getInstance().createXPath(null, expression, Collections.<org.intellij.plugins.xpathView.util.Namespace>emptyList());
XPathSupport.getInstance().createXPath(null, expression, Collections.<Namespace>emptyList());
return true;
} catch (XPathSyntaxException e) {
Messages.showErrorDialog(project, e.getMultilineMessage(), "XPath Syntax Error");
@@ -23,13 +23,12 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlFile;
import com.intellij.ui.EditorTextField;
import com.intellij.ui.EditorComboBox;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.util.ArrayUtil;
@@ -54,14 +53,12 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import javax.xml.namespace.QName;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
@SuppressWarnings("unchecked")
public abstract class InputExpressionDialog<FormType extends InputForm> extends ModeSwitchableDialog {
protected final Project myProject;
protected final FormType myForm;
@@ -72,8 +69,7 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
private final Document myDocument;
private final MultilineEditor myEditor;
private final EditorTextField myComboboxEditor;
private final ComboBox myComboBox = new ComboBox(300);
private final EditorComboBox myComboBox;
private JComponent myEditorComponent;
@Nullable private Set<Namespace> myNamespaceCache;
@@ -97,7 +93,6 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
myModel = new HistoryModel(_history, myDocument);
myEditor = new MultilineEditor(myDocument, project, XPathFileType.XPATH, myModel);
myModel.addListDataListener(new ListDataListener() {
final PsiDocumentManager docMgr = PsiDocumentManager.getInstance(project);
final DaemonCodeAnalyzer analyzer = DaemonCodeAnalyzer.getInstance(project);
public void intervalAdded(ListDataEvent e) {
@@ -116,17 +111,15 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
}
}
});
myComboboxEditor = new EditorTextField(myDocument, project, XPathFileType.XPATH);
myComboBox = new EditorComboBox(myDocument, project, XPathFileType.XPATH);
myComboBox.setRenderer(new ListCellRendererWrapper<HistoryElement>() {
@Override
public void customize(JList list, HistoryElement value, int index, boolean selected, boolean hasFocus) {
setText(value != null ? value.expression : "");
}
@Override
public void customize(JList list, HistoryElement value, int index, boolean selected, boolean hasFocus) {
setText(value != null ? value.expression : "");
}
});
myComboBox.setModel(myModel);
myComboBox.setEditor(new EditorAdapter(myComboboxEditor));
myComboBox.setEditable(true);
myDocument.addDocumentListener(new DocumentAdapter() {
@@ -254,7 +247,7 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
if (getMode() == Mode.ADVANCED) {
return myEditor.getField().getEditor();
} else {
return myComboboxEditor.getEditor();
return myComboBox.getEditorEx();
}
}
@@ -410,35 +403,6 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
}
}
protected class EditorAdapter extends BasicComboBoxEditor {
private final EditorTextField myTf;
public EditorAdapter(EditorTextField tf) {
myTf = tf;
}
public Component getEditorComponent() {
return myTf.getComponent();
}
@Nullable
public Object getItem() {
return myModel.getSelectedItem();
}
public void selectAll() {
myTf.selectAll();
}
public void setItem(Object object) {
if (object == null) {
myEditor.getField().setText("");
} else {
myEditor.getField().setText(((HistoryElement)object).expression);
}
}
}
private static class MyVariableResolver extends SimpleVariableContext {
private final HistoryModel myModel;
@@ -568,7 +532,7 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
@NotNull
public String getText() {
return "Register Namespace Prefix";
return "Register namespace prefix";
}
@NotNull
+1 -2
View File
@@ -27,8 +27,7 @@ setProperty("ch", "$home/community")
setProperty("pythonCommunityHome", "$ch/python")
setProperty("pythonEduHome", "$ch/python/edu")
requireProperty("jdk_bundled_mac", "1.7")
def jdk_bundled_version = p("jdk_bundled_mac") == "1.8" ? "jdk8_mac_redist.tar" : "jdk_mac_redist.tar"
ant.copy(file: "${home}/build/jdk/${jdk_bundled_version}", tofile: "${home}/build/jdk/jdk_mac_redist_for_${buildNumber}.tar")
getBundledJDK(new File("${home}/build/jdk/mac"), "jdk" + p("jdk_bundled_mac"), ".tar", "${home}/build/jdk/jdk_mac_redist_for_${buildNumber}.tar")
// load ApplicationInfo.xml properties
ant.xmlproperty(file: "$pythonEduHome/resources/idea/PyCharmEduApplicationInfo.xml", collapseAttributes: "true")
+32 -3
View File
@@ -96,6 +96,11 @@ PluginManager = None
if SUPPORT_PLUGINS:
from pydevd_plugin_utils import PluginManager
if IS_PY3K:
import pkgutil
else:
from _pydev_imps import _pydev_pkgutil_old as pkgutil
threadingEnumerate = threading.enumerate
threadingCurrentThread = threading.currentThread
@@ -1684,8 +1689,27 @@ class PyDB:
from pydev_monkey import patch_thread_modules
patch_thread_modules()
def get_fullname(self, mod_name):
try:
loader = pkgutil.get_loader(mod_name)
except:
return None
if loader is not None:
for attr in ("get_filename", "_get_filename"):
meth = getattr(loader, attr, None)
if meth is not None:
return meth(mod_name)
return None
def run(self, file, globals=None, locals=None, module=False, set_trace=True):
if module:
filename = self.get_fullname(file)
if filename is None:
sys.stderr.write("No module named %s\n" % file)
return
else:
file = filename
def run(self, file, globals=None, locals=None, set_trace=True):
if os.path.isdir(file):
new_target = os.path.join(file, '__main__.py')
if os.path.isfile(new_target):
@@ -1773,6 +1797,7 @@ def processCommandLine(argv):
setup['save-signatures'] = False
setup['print-in-debugger-startup'] = False
setup['cmd-line'] = False
setup['module'] = False
i = 0
del argv[0]
while (i < len(argv)):
@@ -1816,6 +1841,9 @@ def processCommandLine(argv):
elif (argv[i] == '--cmd-line'):
del argv[i]
setup['cmd-line'] = True
elif (argv[i] == '--module'):
del argv[i]
setup['module'] = True
else:
raise ValueError("unexpected option " + argv[i])
return setup
@@ -2256,6 +2284,7 @@ if __name__ == '__main__':
pass # It's ok not having stackless there...
debugger = PyDB()
is_module = setup['module']
if fix_app_engine_debug:
sys.stderr.write("pydev debugger: google app engine integration enabled\n")
@@ -2270,7 +2299,7 @@ if __name__ == '__main__':
sys.argv.insert(4, '--max_module_instances=1')
# Run the dev_appserver
debugger.run(setup['file'], None, None, set_trace=False)
debugger.run(setup['file'], None, None, is_module, set_trace=False)
else:
# as to get here all our imports are already resolved, the psyco module can be
# changed and we'll still get the speedups in the debugger, as those functions
@@ -2303,7 +2332,7 @@ if __name__ == '__main__':
connected = True # Mark that we're connected when started from inside ide.
globals = debugger.run(setup['file'], None, None)
globals = debugger.run(setup['file'], None, None, is_module)
if setup['cmd-line']:
debugger.wait_for_commands(globals)
@@ -66,6 +66,7 @@ public class PyDebugRunner extends GenericProgramRunner {
public static final String IDE_PROJECT_ROOTS = "IDE_PROJECT_ROOTS";
@SuppressWarnings("SpellCheckingInspection")
public static final String GEVENT_SUPPORT = "GEVENT_SUPPORT";
public static boolean isModule = false;
@Override
@NotNull
@@ -182,14 +183,37 @@ public class PyDebugRunner extends GenericProgramRunner {
final PythonCommandLineState pyState,
final int serverLocalPort) {
return new CommandLinePatcher() {
private void patchExeParams(ParametersList parametersList) {
// we should remove '-m' parameter, but notify debugger of it
// but we can't remove one parameter from group, so we create new parameters group
ParamsGroup newExeParams = new ParamsGroup(PythonCommandLineState.GROUP_EXE_OPTIONS);
int exeParamsIndex = parametersList.getParamsGroups().indexOf(
parametersList.getParamsGroup(PythonCommandLineState.GROUP_EXE_OPTIONS));
ParamsGroup exeParamsOld = parametersList.removeParamsGroup(exeParamsIndex);
isModule = false;
for (String param: exeParamsOld.getParameters()) {
if (!param.equals("-m")) {
newExeParams.addParameter(param);
} else {
isModule = true;
}
}
parametersList.addParamsGroupAt(exeParamsIndex, newExeParams);
}
@Override
public void patchCommandLine(GeneralCommandLine commandLine) {
// script name is the last parameter; all other params are for python interpreter; insert just before name
final ParametersList parametersList = commandLine.getParametersList();
ParametersList parametersList = commandLine.getParametersList();
@SuppressWarnings("ConstantConditions") @NotNull
ParamsGroup debugParams = parametersList.getParamsGroup(PythonCommandLineState.GROUP_DEBUGGER);
patchExeParams(parametersList);
@SuppressWarnings("ConstantConditions") @NotNull
ParamsGroup exeParams = parametersList.getParamsGroup(PythonCommandLineState.GROUP_EXE_OPTIONS);
@@ -218,6 +242,10 @@ public class PyDebugRunner extends GenericProgramRunner {
debugParams.addParameter("--multiproc");
}
if (isModule) {
debugParams.addParameter("--module");
}
if (ApplicationManager.getApplication().isUnitTestMode()) {
debugParams.addParameter("--DEBUG");
}
@@ -22,26 +22,39 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
/**
* Joins lines sanely.
* - statement lines: add a semicolon;
* - list-like lines: keep one space after comma;
* - lines inside a multiline string: remove excess indentation;
* - multi-constant string like "a" "b": join into one;
* - comment and comment: remove indentation and hash sign;
* - second line is 'class' or 'def': fail.
* <br/>
* User: dcheryasov
* Date: Sep 6, 2010 2:25:48 AM
* <ul>
* <li>statement lines: add a semicolon;</li>
* <li>list-like lines: keep one space after comma;</li>
* <li>lines inside a multiline string: remove excess indentation;</li>
* <li>multi-constant string like "a" "b": join into one;</li>
* <li>comment and comment: remove indentation and hash sign;</li>
* <li>second line is 'class' or 'def': fail.</li>
* </ul>
*
* @author dcheryasov
*/
public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
private final static Joiner[] JOINERS = {
new OpenBracketJoiner(),
new CloseBracketJoiner(),
new StringLiteralJoiner(),
new StmtJoiner(), // strings before stmts to let doc strings join
new BinaryExprJoiner(),
new CommentJoiner(),
new StripBackslashJoiner()
};
@Override
public int tryJoinLines(Document document, PsiFile file, int start, int end) {
@@ -49,203 +62,117 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
}
@Override
public int tryJoinRawLines(Document document, PsiFile file, int start, int end) {
public int tryJoinRawLines(@NotNull Document document, PsiFile file, int start, int end) {
if (!(file instanceof PyFile)) return CANNOT_JOIN;
// step back the probable "\" and space before it.
int i = start;
CharSequence text = document.getCharsSequence();
if (i>= 0 && text.charAt(i) == '\n') i -=1;
if (i>= 0 && text.charAt(i) == '\\') i -=1;
while (i>=0 && text.charAt(i) == ' ' || text.charAt(i) == '\t') i -=1;
if (i < 0) return CANNOT_JOIN; // TODO: join with empty BOF, too
final CharSequence text = document.getCharsSequence();
if (start >= 0 && text.charAt(start) == '\n') start -= 1;
if (start >= 0 && text.charAt(start) == '\\') start -= 1;
while (start >= 0 && text.charAt(start) == ' ' || text.charAt(start) == '\t') {
start -= 1;
}
if (start < 0) {
return CANNOT_JOIN; // TODO: join with empty BOF, too
}
// detect elements around the join
PsiElement left_element = file.findElementAt(i);
PsiElement right_element = file.findElementAt(end);
if (left_element != null && right_element != null) {
PyExpression left_expr = PsiTreeUtil.getParentOfType(left_element, PyExpression.class);
if (left_expr instanceof PsiFile) left_expr = null;
PyExpression right_expr = PsiTreeUtil.getParentOfType(right_element, PyExpression.class);
if (right_expr instanceof PsiFile) right_expr = null;
final PsiElement leftElement = file.findElementAt(start);
final PsiElement rightElement = file.findElementAt(end);
if (leftElement != null && rightElement != null) {
final PyExpression leftExpr = PsiTreeUtil.getParentOfType(leftElement, PyExpression.class);
final PyExpression rightExpr = PsiTreeUtil.getParentOfType(rightElement, PyExpression.class);
Joiner[] joiners = { // these are featherweight, will create and gc instantly
new OpenBracketJoiner(), new CloseBracketJoiner(),
new StringLiteralJoiner(), new StmtJoiner(), // strings before stmts to let doc strings join
new BinaryExprJoiner(), new ListLikeExprJoiner(),
new CommentJoiner(),
};
final Request request = new Request(document, start, end, leftElement, leftExpr, rightElement, rightExpr);
Request request = new Request(document, left_element, left_expr, right_element, right_expr);
for (Joiner joiner : joiners) {
Result res = joiner.join(request);
for (Joiner joiner : JOINERS) {
final Result res = joiner.join(request);
if (res != null) {
final int cut_start = i + 1 - res.getCutFromLeft();
document.deleteString(cut_start, end + res.getCutIntoRight());
document.insertString(cut_start, res.getInsert());
return cut_start + res.getCursorOffset();
}
}
// single string case PY-4375
final PyExpression leftExpression = request.leftExpr();
final PyExpression rightExpression = request.rightExpr();
if (request.leftElem() == request.rightElem()) {
IElementType type = request.leftElem().getNode().getElementType();
if (PyTokenTypes.SINGLE_QUOTED_STRING == type || PyTokenTypes.SINGLE_QUOTED_UNICODE == type) {
if (leftExpression == null) return CANNOT_JOIN;
if (removeBackSlash(document, leftExpression, false)) {
return leftExpression.getTextOffset();
}
}
}
PsiElement expression = null;
if (leftExpression != null && rightExpression != null) {
if (PsiTreeUtil.isAncestor(leftExpression, rightExpression, false))
expression = leftExpression;
else if (PsiTreeUtil.isAncestor(rightExpression, leftExpression, false))
expression = rightExpression;
if (expression != null && !(expression instanceof PyStringLiteralExpression)) {
if (removeBackSlash(document, expression, true)) {
return expression.getTextOffset();
}
final int cutStart = start + 1 - res.cutFromLeft;
document.replaceString(cutStart, end + res.cutIntoRight, res.replacement);
return cutStart + res.caretOffset;
}
}
}
return CANNOT_JOIN;
}
private static boolean removeBackSlash(Document document, PsiElement element, boolean trim) {
String[] substrings = element.getText().split("\n");
if (substrings.length != 1) {
StringBuilder replacement = new StringBuilder();
for (int i = 0; i < substrings.length; i++) {
String string = substrings[i];
if (trim) {
string = StringUtil.trimLeading(string);
}
if (string.trim().endsWith("\\")) {
replacement.append(string.substring(0, string.length() - 1));
}
else {
replacement.append(string);
}
if (i != substrings.length - 1 && !(element instanceof PyReferenceExpression) &&
!(element instanceof PyStringLiteralExpression)) {
replacement.append(" ");
}
}
document.replaceString(element.getTextOffset(), element.getTextOffset()+element.getTextLength(), replacement);
return true;
}
return false;
}
// a dumb immutable result holder
private static class Result {
final String myInsert;
final int myOffset;
final int myCutFromLeft;
final int myCutIntoRight;
final String replacement;
final int caretOffset;
final int cutFromLeft;
final int cutIntoRight;
/**
* Result of a join operation.
* @param insert: what string to insert at start position
*
* @param replacement: what string to insert at start position
* @param cursorOffset: how to move cursor relative to start (0 = stand at start)
*/
Result(String insert, int cursorOffset) {
myInsert = insert;
myOffset = cursorOffset;
myCutFromLeft = 0;
myCutIntoRight = 0;
Result(@NotNull String replacement, int cursorOffset) {
this(replacement, cursorOffset, 0, 0);
}
/**
* Result of a join operation.
* @param insert what to insert into the cut place
*
* @param replacement what to insert into the cut place
* @param cursorOffset where to put cursor, relative to the start cursorOffset of cutting
* @param cutFromLeft how many chars to cut from the end on left string, >0 moves start cursorOffset of cutting to the left.
* @param cutFromLeft how many chars to cut from the end on left string, >0 moves start cursorOffset of cutting to the left.
* @param cutIntoRight how many chars to cut from the beginning on right string, >0 moves start cursorOffset of cutting to the right.
*/
private Result(String insert, int cursorOffset, int cutFromLeft, int cutIntoRight) {
myCutFromLeft = cutFromLeft;
myCutIntoRight = cutIntoRight;
myInsert = insert;
myOffset = cursorOffset;
}
public String getInsert() {
return myInsert;
}
public int getCursorOffset() {
return myOffset;
}
public int getCutFromLeft() {
return myCutFromLeft;
}
public int getCutIntoRight() {
return myCutIntoRight;
Result(@NotNull String replacement, int cursorOffset, int cutFromLeft, int cutIntoRight) {
this.cutFromLeft = cutFromLeft;
this.cutIntoRight = cutIntoRight;
this.replacement = replacement;
caretOffset = cursorOffset;
}
}
// a dumb immutable request items holder
private static class Request {
final Document myDocument;
final PsiElement myLeftElem;
final PsiElement myRightElem;
final PyExpression myLeftExpr;
final PyExpression myRightExpr;
final Document document;
final PsiElement leftElem;
final PsiElement rightElem;
final PyExpression leftExpr;
final PyExpression rightExpr;
final int secondLineStartOffset;
final int firstLineEndOffset;
private Request(Document document, PsiElement leftElem, PyExpression leftExpr, PsiElement rightElem, PyExpression rightExpr) {
myDocument = document;
myLeftElem = leftElem;
myLeftExpr = leftExpr;
myRightElem = rightElem;
myRightExpr = rightExpr;
private Request(@NotNull Document document,
int firstLineEndOffset,
int secondLineStartOffset,
@NotNull PsiElement leftElem,
@Nullable PyExpression leftExpr,
@NotNull PsiElement rightElem,
@Nullable PyExpression rightExpr) {
this.document = document;
this.firstLineEndOffset = firstLineEndOffset;
this.secondLineStartOffset = secondLineStartOffset;
this.leftElem = leftElem;
this.rightElem = rightElem;
this.leftExpr = leftExpr;
this.rightExpr = rightExpr;
}
public Document document() {
return myDocument;
}
public PsiElement leftElem() {
return myLeftElem;
}
public PyExpression leftExpr() {
return myLeftExpr;
}
public PsiElement rightElem() {
return myRightElem;
}
public PyExpression rightExpr() {
return myRightExpr;
}
}
private static abstract class Joiner {
private interface Joiner {
/**
* Try to join lines.
*
* @param req@return null if cannot join, or ("what to insert", cursor_offset).
*/
@Nullable
abstract public Result join(Request req);
Result join(@NotNull Request req);
}
private static class OpenBracketJoiner extends Joiner {
private static TokenSet OPENS = TokenSet.create(PyTokenTypes.LBRACKET, PyTokenTypes.LBRACE, PyTokenTypes.LPAR);
private static class OpenBracketJoiner implements Joiner {
private static final TokenSet OPENS = TokenSet.create(PyTokenTypes.LBRACKET, PyTokenTypes.LBRACE, PyTokenTypes.LPAR);
@Override
public Result join(Request req) {
if (OPENS.contains(req.leftElem().getNode().getElementType())) {
public Result join(@NotNull Request req) {
if (OPENS.contains(req.leftElem.getNode().getElementType())) {
// TODO: look at settings for space after opening paren
return new Result("", 0);
}
@@ -253,11 +180,12 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
}
}
private static class CloseBracketJoiner extends Joiner {
private static TokenSet CLOSES = TokenSet.create(PyTokenTypes.RBRACKET, PyTokenTypes.RBRACE, PyTokenTypes.RPAR);
private static class CloseBracketJoiner implements Joiner {
private static final TokenSet CLOSES = TokenSet.create(PyTokenTypes.RBRACKET, PyTokenTypes.RBRACE, PyTokenTypes.RPAR);
@Override
public Result join(Request req) {
if (CLOSES.contains(req.rightElem().getNode().getElementType())) {
public Result join(@NotNull Request req) {
if (CLOSES.contains(req.rightElem.getNode().getElementType())) {
// TODO: look at settings for space before closing paren
return new Result("", 0);
}
@@ -265,10 +193,10 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
}
}
private static class BinaryExprJoiner extends Joiner {
private static class BinaryExprJoiner implements Joiner {
@Override
public Result join(Request req) {
if (req.leftExpr() instanceof PyBinaryExpression || req.rightExpr() instanceof PyBinaryExpression) {
public Result join(@NotNull Request req) {
if (req.leftExpr instanceof PyBinaryExpression || req.rightExpr instanceof PyBinaryExpression) {
// TODO: look at settings for space around binary exprs
return new Result(" ", 1);
}
@@ -276,29 +204,13 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
}
}
private static class ListLikeExprJoiner extends Joiner {
private static class StmtJoiner implements Joiner {
@Override
public Result join(Request req) {
final boolean left_is_list_like = PyUtil.instanceOf(req.leftExpr(), PyListLiteralExpression.class, PyTupleExpression.class);
if (left_is_list_like || PyUtil.instanceOf(req.rightExpr(), PyListLiteralExpression.class, PyTupleExpression.class)
) {
String insert = "";
if (left_is_list_like) { // we join "a, \n b", not "a \n ,b"
insert = " "; // TODO: look at settings for space after commas in lists
}
return new Result(insert, insert.length());
}
return null;
}
}
private static class StmtJoiner extends Joiner {
@Override
public Result join(Request req) {
PyStatement left_stmt = PsiTreeUtil.getParentOfType(req.leftExpr(), PyStatement.class);
if (left_stmt != null) {
PyStatement right_stmt = PsiTreeUtil.getParentOfType(req.rightExpr(), PyStatement.class);
if (right_stmt != null && right_stmt != left_stmt) {
public Result join(@NotNull Request req) {
final PyStatement leftStmt = PsiTreeUtil.getParentOfType(req.leftExpr, PyStatement.class);
if (leftStmt != null) {
final PyStatement rightStmt = PsiTreeUtil.getParentOfType(req.rightExpr, PyStatement.class);
if (rightStmt != null && rightStmt != leftStmt) {
// TODO: look at settings for space after semicolon
return new Result("; ", 1); // cursor after semicolon
}
@@ -307,34 +219,33 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
}
}
private static class StringLiteralJoiner extends Joiner {
private static class StringLiteralJoiner implements Joiner {
@Override
public Result join(Request req) {
if (req.leftElem() != req.rightElem()) {
final PsiElement parent = req.rightElem().getParent();
if ((req.leftElem().getParent() == parent && parent instanceof PyStringLiteralExpression) ||
(req.leftExpr() instanceof PyStringLiteralExpression && req.rightExpr() instanceof PyStringLiteralExpression)
) {
public Result join(@NotNull Request req) {
if (req.leftElem != req.rightElem) {
final PsiElement parent = req.rightElem.getParent();
if ((req.leftElem.getParent() == parent && parent instanceof PyStringLiteralExpression) ||
(req.leftExpr instanceof PyStringLiteralExpression && req.rightExpr instanceof PyStringLiteralExpression)) {
// two quoted strings close by
CharSequence text = req.document().getCharsSequence();
StrMod left_mod = new StrMod(text, req.leftElem().getTextRange());
StrMod right_mod = new StrMod(text, req.rightElem().getTextRange());
if (left_mod.isOk() && right_mod.isOk()) {
final String lquo = left_mod.quote();
if (left_mod.equals(right_mod)) {
return new Result("", 0, lquo.length(), right_mod.getStartPadding());
final CharSequence text = req.document.getCharsSequence();
final StrMod leftMod = new StrMod(text, req.leftElem.getTextRange());
final StrMod rightMod = new StrMod(text, req.rightElem.getTextRange());
if (leftMod.isOk() && rightMod.isOk()) {
final String lquo = leftMod.quote();
if (leftMod.equals(rightMod)) {
return new Result("", 0, lquo.length(), rightMod.getStartPadding());
}
else if (left_mod.compatibleTo(right_mod) && lquo.length() == 1 && right_mod.quote().length() == 1) {
else if (leftMod.compatibleTo(rightMod) && lquo.length() == 1 && rightMod.quote().length() == 1) {
// maybe fit one literal's quotes to match other's
if (! containsChar(text, right_mod.getInnerRange(), left_mod.quote().charAt(0))) {
int quote_pos = right_mod.getInnerRange().getEndOffset();
req.document().replaceString(quote_pos, quote_pos+1, left_mod.quote());
return new Result("", 0, left_mod.quote().length(), right_mod.getStartPadding());
if (!containsChar(text, rightMod.getInnerRange(), leftMod.quote().charAt(0))) {
final int quotePos = rightMod.getInnerRange().getEndOffset();
req.document.replaceString(quotePos, quotePos + 1, leftMod.quote());
return new Result("", 0, leftMod.quote().length(), rightMod.getStartPadding());
}
else if (! containsChar(text, left_mod.getInnerRange(), right_mod.quote().charAt(0))) {
int quote_pos = left_mod.getInnerRange().getStartOffset()-1;
req.document().replaceString(quote_pos, quote_pos+1, right_mod.quote());
return new Result("", 0, left_mod.quote().length(), right_mod.getStartPadding());
else if (!containsChar(text, leftMod.getInnerRange(), rightMod.quote().charAt(0))) {
final int quotePos = leftMod.getInnerRange().getStartOffset() - 1;
req.document.replaceString(quotePos, quotePos + 1, rightMod.quote());
return new Result("", 0, leftMod.quote().length(), rightMod.getStartPadding());
}
}
}
@@ -343,71 +254,71 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
return null;
}
protected static boolean containsChar(CharSequence text, TextRange range, char c) {
for (int i=range.getStartOffset(); i <= range.getEndOffset(); i+=1) {
if (text.charAt(i) == c) return true;
}
return false;
protected static boolean containsChar(@NotNull CharSequence text, @NotNull TextRange range, char c) {
return StringUtil.contains(text, range.getStartOffset(), range.getEndOffset(), c);
}
private static class StrMod {
private final String myPrefix; // "u", "b", or ""
private final boolean myRaw; // is raw or not
private final String myQuote; // single or double, one or triple.
private final boolean myOk; // true if parsing went ok
private final TextRange myInnerRange;
public StrMod(CharSequence text, TextRange range) {
private static class StrMod {
@NotNull private final String myPrefix; // "u", "b", or ""
private final boolean myRaw; // is raw or not
@NotNull private final String myQuote; // single or double, one or triple.
@Nullable private final TextRange myInnerRange;
public StrMod(@NotNull CharSequence text, @NotNull TextRange range) {
int pos = range.getStartOffset();
char c = text.charAt(pos);
if ("Uu".indexOf(c) > -1 || "Bb".indexOf(c) > -1) {
myPrefix = String.valueOf(c).toLowerCase();
pos +=1;
myPrefix = String.valueOf(c).toLowerCase(Locale.US);
pos += 1;
c = text.charAt(pos);
}
else myPrefix = "";
else {
myPrefix = "";
}
if ("Rr".indexOf(c) > -1) {
myRaw = true;
pos +=1;
pos += 1;
c = text.charAt(pos);
}
else myRaw = false;
char quote = c;
else {
myRaw = false;
}
final char quote = c;
if ("'\"".indexOf(quote) < 0) {
myInnerRange = null;
myQuote = "";
myOk = false;
return; // failed to find a quote
}
// TODO: we could run a simple but complete parser here, only checking escapes
if (range.getLength() >= 6 && text.charAt(pos+1) == quote && text.charAt(pos+2) == quote) {
myQuote = text.subSequence(pos, pos+3).toString();
if (!myQuote.equals(text.subSequence(range.getEndOffset()-3, range.getEndOffset()).toString())) {
if (range.getLength() >= 6 && text.charAt(pos + 1) == quote && text.charAt(pos + 2) == quote) {
myQuote = text.subSequence(pos, pos + 3).toString();
if (!myQuote.equals(text.subSequence(range.getEndOffset() - 3, range.getEndOffset()).toString())) {
myInnerRange = null;
myOk = false;
return;
}
}
else {
myQuote = text.subSequence(pos, pos+1).toString();
if (!myQuote.equals(text.subSequence(range.getEndOffset()-1, range.getEndOffset()).toString())) {
myQuote = text.subSequence(pos, pos + 1).toString();
if (!myQuote.equals(text.subSequence(range.getEndOffset() - 1, range.getEndOffset()).toString())) {
myInnerRange = null;
myOk = false;
return;
}
}
myInnerRange = TextRange.from(range.getStartOffset()+getStartPadding(), range.getLength()-getStartPadding()-quote().length());
myOk = true;
myInnerRange = TextRange.from(range.getStartOffset() + getStartPadding(), range.getLength() - getStartPadding() - quote().length());
}
public boolean isOk() {
return myOk;
return myInnerRange != null;
}
@NotNull
public String prefix() {
return myPrefix;
}
@NotNull
public String quote() {
return myQuote;
}
@@ -420,12 +331,7 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
public boolean equals(Object o) {
if (o instanceof StrMod) {
final StrMod other = (StrMod)o;
return (
myOk && other.isOk() &&
myRaw == other.isRaw() &&
myPrefix.equals(other.prefix()) &&
myQuote.equals(other.quote())
);
return compatibleTo(other) && myQuote.equals(other.quote());
}
return false;
}
@@ -434,44 +340,60 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
* @return combined length of initial modifier letters and opening quotes
*/
public int getStartPadding() {
return myQuote.length() + myPrefix.length() + (myRaw? 1 : 0);
return myQuote.length() + myPrefix.length() + (myRaw ? 1 : 0);
}
/**
* @param other
* @return true iff this and other have the same byte/unicode and raw prefixes.
*/
public boolean compatibleTo(StrMod other) {
return myOk && other.isOk() && myRaw == other.isRaw() && myPrefix.equals(other.prefix());
public boolean compatibleTo(@NotNull StrMod other) {
return isOk() && other.isOk() && myRaw == other.isRaw() && myPrefix.equals(other.prefix());
}
/**
* @return range of text part inside quotes
*/
@Nullable
public TextRange getInnerRange() {
return myInnerRange;
}
}
}
private static class CommentJoiner extends Joiner {
private static class CommentJoiner implements Joiner {
@Override
public Result join(Request req) {
if (req.leftElem() instanceof PsiComment && req.rightElem() instanceof PsiComment) {
CharSequence text = req.document().getCharsSequence();
final TextRange right_range = req.rightElem().getTextRange();
int initial_pos = right_range.getStartOffset() + 1;
int pos = initial_pos; // cut '#'
int last = right_range.getEndOffset();
public Result join(@NotNull Request req) {
if (req.leftElem instanceof PsiComment && req.rightElem instanceof PsiComment) {
final CharSequence text = req.document.getCharsSequence();
final TextRange rightRange = req.rightElem.getTextRange();
final int initialPos = rightRange.getStartOffset() + 1;
int pos = initialPos; // cut '#'
final int last = rightRange.getEndOffset();
while (pos < last && " \t".indexOf(text.charAt(pos)) >= 0) pos += 1;
int right = pos - initial_pos + 1; // account for the '#'
final int right = pos - initialPos + 1; // account for the '#'
return new Result(" ", 0, 0, right);
}
return null;
}
}
private static class StripBackslashJoiner implements Joiner {
static final TokenSet SINGLE_QUOTED_STRINGS = TokenSet.create(PyTokenTypes.SINGLE_QUOTED_STRING, PyTokenTypes.SINGLE_QUOTED_UNICODE);
@Nullable
@Override
public Result join(@NotNull Request req) {
final String gap = req.document.getText(new TextRange(req.firstLineEndOffset + 1, req.secondLineStartOffset));
final int index = gap.indexOf('\\');
if (index >= 0) {
if (req.leftElem == req.rightElem && SINGLE_QUOTED_STRINGS.contains(req.leftElem.getNode().getElementType())) {
return new Result(gap.replaceFirst("\\\\\\n", ""), 0);
}
else {
return new Result(gap.substring(0, index), 0);
}
}
return null;
}
}
}
@@ -0,0 +1 @@
from foo import bar, baz
@@ -0,0 +1,2 @@
from foo import bar, \
baz
@@ -0,0 +1 @@
import foo, bar
@@ -0,0 +1,2 @@
import foo, \
bar
@@ -1,2 +1 @@
if True:
return "No special handling"
if True: return "No special handling"
@@ -1,2 +1 @@
a = 1 # surprise!
b = 2
a = 1 # surprise! b = 2
@@ -1,2 +1 @@
print (r"See, \n separates two lines: "
"this and\nthe other")
print (r"See, \n separates two lines: " "this and\nthe other")
@@ -1,2 +1 @@
a = (u"Ein Deutsche Text. "
"An English text")
a = (u"Ein Deutsche Text. " "An English text")
@@ -1,3 +1,2 @@
<caret>'''This doc comment
is quite separate'''
'''This doc comment is quite separate'''
"""from the literal below"""
@@ -15,70 +15,137 @@
*/
package com.jetbrains.python;
import com.intellij.codeInsight.editorActions.JoinRawLinesHandlerDelegate;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.jetbrains.python.editor.PyJoinLinesHandler;
import com.intellij.openapi.actionSystem.IdeActions;
import com.jetbrains.python.fixtures.PyTestCase;
/**
* Tests the "Join lines" handler.
* <br/>
* User: dcheryasov
* Date: 1/29/11 2:33 AM
*
* @author dcheryasov
*/
public class PyJoinLinesTest extends PyTestCase {
private void doTest() {
final String path = "joinLines/";
myFixture.configureByFile(path + getTestName(false) + ".py");
// detect whitespace around EOL, the way JoinLinesHandler does.
final Editor editor = myFixture.getEditor();
final Document doc = editor.getDocument();
final int caret_line = doc.getLineNumber(editor.getCaretModel().getOffset());
final int eol_pos = doc.getLineEndOffset(caret_line);
CharSequence text = doc.getCharsSequence();
int i = eol_pos;
while (" \n\t".indexOf(text.charAt(i)) >= 0) i -= 1;
final int start = i+1;
i = eol_pos;
while (" \n\t".indexOf(text.charAt(i)) >= 0) i += 1;
final int end = i;
final JoinRawLinesHandlerDelegate handler = new PyJoinLinesHandler();
WriteCommandAction.runWriteCommandAction(myFixture.getProject(), new Runnable() {
@Override
public void run() {
handler.tryJoinRawLines(doc, myFixture.getFile(), start, end);
}
});
myFixture.checkResultByFile(path + getTestName(false) + "-after.py");
myFixture.configureByFile("joinLines/" + getTestName(false) + ".py");
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_JOIN_LINES);
myFixture.checkResultByFile("joinLines/" + getTestName(false) + "-after.py");
}
public void testBinaryOpBelow() { doTest(); }
public void testBinaryOp() { doTest(); }
public void testDictLCurly() { doTest(); }
public void testDictRCurly() { doTest(); }
public void testListLBracket() { doTest(); }
public void testList() { doTest(); }
public void testListRBracket() { doTest(); }
public void testStatementColon() { doTest(); }
public void testStatementComment() { doTest(); }
public void testStatementCommentStatement() { doTest(); }
public void testStringDifferentOneQuotes() { doTest(); }
public void testStringDifferentOneQuotesBelow() { doTest(); }
public void testStringOneQuoteEscEOL() { doTest(); }
public void testStringOneQuotePlainRaw() { doTest(); }
public void testStringOneQuotePlainU() { doTest(); }
public void testStringTripleQuotesDifferent() { doTest(); }
public void testStringTripleQuotes() { doTest(); }
public void testTupleLPar() { doTest(); }
public void testTuple() { doTest(); }
public void testTupleRPar() { doTest(); }
public void testTwoComments() { doTest(); }
public void testTwoComments2() { doTest(); } // PY-7286
public void testTwoStatements() { doTest(); }
public void testStringWithSlash() { doTest(); }
public void testListOfStrings() { doTest(); }
public void testLongExpression() { doTest(); }
public void testListComprehension() { doTest(); }
public void testBinaryOpBelow() {
doTest();
}
public void testBinaryOp() {
doTest();
}
public void testDictLCurly() {
doTest();
}
public void testDictRCurly() {
doTest();
}
public void testListLBracket() {
doTest();
}
public void testList() {
doTest();
}
public void testListRBracket() {
doTest();
}
public void testStatementColon() {
doTest();
}
public void testStatementComment() {
doTest();
}
public void testStatementCommentStatement() {
doTest();
}
public void testStringDifferentOneQuotes() {
doTest();
}
public void testStringDifferentOneQuotesBelow() {
doTest();
}
public void testStringOneQuoteEscEOL() {
doTest();
}
public void testStringOneQuotePlainRaw() {
doTest();
}
public void testStringOneQuotePlainU() {
doTest();
}
public void testStringTripleQuotesDifferent() {
doTest();
}
public void testStringTripleQuotes() {
doTest();
}
public void testTupleLPar() {
doTest();
}
public void testTuple() {
doTest();
}
public void testTupleRPar() {
doTest();
}
public void testTwoComments() {
doTest();
}
// PY-7286
public void testTwoComments2() {
doTest();
}
public void testTwoStatements() {
doTest();
}
public void testStringWithSlash() {
doTest();
}
public void testListOfStrings() {
doTest();
}
public void testLongExpression() {
doTest();
}
public void testListComprehension() {
doTest();
}
// PY-15564
public void testBackslashBetweenTargetsInImport() {
doTest();
}
// PY-15564
public void testBackslashBetweenTargetsInFromImport() {
doTest();
}
}