mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master' into amakeev/symlinks
This commit is contained in:
@@ -97,6 +97,12 @@ public final class RegExpCompletionContributor extends CompletionContributor {
|
||||
final ElementPattern<PsiElement> propertyNamePattern
|
||||
= psiElement().afterLeaf(psiElement().withText("{").afterLeaf(propertyPattern));
|
||||
extend(CompletionType.BASIC, propertyNamePattern, new PropertyNameCompletionProvider());
|
||||
|
||||
final PsiElementPattern.Capture<PsiElement> namedCharacterPattern = psiElement().withText("N");
|
||||
extend(CompletionType.BASIC, psiElement().afterLeaf(namedCharacterPattern),
|
||||
new NamedCharacterCompletionProvider(true));
|
||||
extend(CompletionType.BASIC, psiElement().afterLeaf(psiElement(RegExpTT.LBRACE).afterLeaf(namedCharacterPattern)),
|
||||
new NamedCharacterCompletionProvider(false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
package org.intellij.lang.regexp;
|
||||
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.ClassExtension;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.FileContextUtil;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.intellij.lang.regexp.psi.*;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -51,36 +51,19 @@ public final class RegExpLanguageHosts extends ClassExtension<RegExpLanguageHost
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
private static RegExpLanguageHost findRegExpHost(@Nullable final PsiElement element) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode() && myHost != null) {
|
||||
return myHost;
|
||||
}
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
PsiLanguageInjectionHost injectionHost = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element);
|
||||
final RegExpLanguageHost host = getRegExpHost(injectionHost);
|
||||
if (host != null) {
|
||||
return host;
|
||||
if (ApplicationManager.getApplication().isUnitTestMode() && myHost != null) {
|
||||
return myHost;
|
||||
}
|
||||
final PsiFile file = element.getContainingFile();
|
||||
final SmartPsiElementPointer pointer = file.getUserData(FileContextUtil.INJECTED_IN_ELEMENT);
|
||||
if (pointer == null) {
|
||||
return null;
|
||||
final PsiElement context = file.getContext();
|
||||
if (context instanceof RegExpLanguageHost) {
|
||||
return (RegExpLanguageHost)context;
|
||||
}
|
||||
final PsiElement pointerElement = pointer.getElement();
|
||||
if (pointerElement == null) {
|
||||
return null;
|
||||
}
|
||||
return getRegExpHost(pointerElement);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static RegExpLanguageHost getRegExpHost(@Nullable PsiElement languageInjectionHostElement) {
|
||||
if (languageInjectionHostElement instanceof RegExpLanguageHost) {
|
||||
return (RegExpLanguageHost)languageInjectionHostElement;
|
||||
}
|
||||
if (languageInjectionHostElement != null) {
|
||||
return INSTANCE.forClass(languageInjectionHostElement.getClass());
|
||||
if (context != null) {
|
||||
return INSTANCE.forClass(context.getClass());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -171,7 +154,6 @@ public final class RegExpLanguageHosts extends ClassExtension<RegExpLanguageHost
|
||||
|
||||
public boolean supportsNamedCharacters(@NotNull final RegExpNamedCharacter namedCharacter) {
|
||||
final RegExpLanguageHost host = findRegExpHost(namedCharacter);
|
||||
System.out.println("host = " + host);
|
||||
return host != null && host.supportsNamedCharacters(namedCharacter);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,14 +33,16 @@ public class UnicodeCharacterNames {
|
||||
try {
|
||||
final Class<?> aClass = Class.forName("java.lang.CharacterName");
|
||||
final Method initNamePool = ReflectionUtil.getDeclaredMethod(aClass, "initNamePool");
|
||||
final int[][] lookup2d = ReflectionUtil.getField(aClass, null, int[][].class, "lookup");
|
||||
if (initNamePool != null && lookup2d != null) { // jdk 8
|
||||
byte[] namePool = (byte[])initNamePool.invoke(null);
|
||||
if (initNamePool != null) { // jdk 8
|
||||
byte[] namePool = (byte[])initNamePool.invoke(null); // initializes "lookup" field
|
||||
final int[][] lookup2d = ReflectionUtil.getStaticFieldValue(aClass, int[][].class, "lookup");
|
||||
if (lookup2d == null) {
|
||||
return;
|
||||
}
|
||||
for (int[] indexes : lookup2d) {
|
||||
if (indexes != null) {
|
||||
for (int index : indexes) {
|
||||
if (index != 0) {
|
||||
;
|
||||
final String name = new String(namePool, index >>> 8, index & 0xff, AsciiUtil.ASCII_CHARSET);
|
||||
consumer.accept(name);
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
*/
|
||||
package org.intellij.lang.regexp;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -57,6 +59,17 @@ public class RegExpCompletionTest extends CodeInsightFixtureTestCase {
|
||||
myFixture.checkResult("[[:^alpha:]<caret>");
|
||||
}
|
||||
|
||||
public void testNamedCharacter() {
|
||||
myFixture.configureByText(RegExpFileType.INSTANCE, "\\\\N{SMILE<caret>}");
|
||||
final LookupElement[] elements = myFixture.completeBasic();
|
||||
final List<String> strings = ContainerUtil.map(elements, LookupElement::getLookupString);
|
||||
assertEquals(Arrays.asList("SMILE", "SMILING FACE WITH SMILING EYES", "SMILING FACE WITH HEART-SHAPED EYES",
|
||||
"SMILING CAT FACE WITH HEART-SHAPED EYES", "SMILING FACE WITH OPEN MOUTH AND SMILING EYES",
|
||||
"SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES", "CAT FACE WITH WRY SMILE",
|
||||
"GRINNING CAT FACE WITH SMILING EYES", "GRINNING FACE WITH SMILING EYES",
|
||||
"KISSING FACE WITH SMILING EYES"), strings);
|
||||
}
|
||||
|
||||
public void testBackSlashVariants() throws Throwable {
|
||||
List<String> nameList =
|
||||
new ArrayList<>(Arrays.asList("d", "D", "s", "S", "w", "W", "b", "B", "A", "G", "Z", "z", "Q", "E",
|
||||
|
||||
@@ -65,6 +65,12 @@ abstract class BuildContext {
|
||||
|
||||
abstract boolean includeBreakGenLibraries()
|
||||
|
||||
/**
|
||||
* If the method returns {@code false} 'idea.jars.nocopy' property will be set to {@code true} in idea.properties by default. Otherwise it
|
||||
* won't be set and the IDE will copy library *.jar files to avoid their locking when running under Windows.
|
||||
*/
|
||||
abstract boolean shouldIDECopyJarsByDefault()
|
||||
|
||||
abstract void patchInspectScript(String path)
|
||||
|
||||
abstract String getAdditionalJvmArguments()
|
||||
|
||||
@@ -178,6 +178,7 @@ class CommunityRepositoryModules {
|
||||
plugin("course-creator"),
|
||||
plugin("course-creator-python"),
|
||||
plugin("ipnb"),
|
||||
plugin("IntelliLang-python")
|
||||
plugin("IntelliLang-python"),
|
||||
plugin("python-rest")
|
||||
]
|
||||
}
|
||||
@@ -78,7 +78,7 @@ abstract class WindowsDistributionCustomizer {
|
||||
/**
|
||||
* The returned name will be used to create links on Desktop
|
||||
*/
|
||||
String fullNameIncludingEditionAndVendor(ApplicationInfoProperties applicationInfo) { applicationInfo.shortCompanyName + " " + applicationInfo.productName }
|
||||
String fullNameIncludingEditionAndVendor(ApplicationInfoProperties applicationInfo) { applicationInfo.shortCompanyName + " " + fullNameIncludingEdition(applicationInfo) }
|
||||
|
||||
String uninstallFeedbackPageUrl(ApplicationInfoProperties applicationInfo) {
|
||||
return null
|
||||
|
||||
@@ -259,8 +259,18 @@ class BuildContextImpl extends BuildContext {
|
||||
|
||||
@Override
|
||||
boolean includeBreakGenLibraries() {
|
||||
return isJavaSupportedInProduct()
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean shouldIDECopyJarsByDefault() {
|
||||
return isJavaSupportedInProduct()
|
||||
}
|
||||
|
||||
private boolean isJavaSupportedInProduct() {
|
||||
def productLayout = productProperties.productLayout
|
||||
return productLayout.mainJarName == null || //todo[nik] remove this condition later
|
||||
return productLayout.mainJarName == null ||
|
||||
//todo[nik] remove this condition later; currently build scripts for IDEA don't fully migrated to the new scheme
|
||||
productLayout.includedPlatformModules.contains("execution-impl")
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class BuildTasksImpl extends BuildTasks {
|
||||
|
||||
@Override
|
||||
void buildSearchableOptions(String targetModuleName, List<String> modulesToIndex, List<String> pathsToLicenses) {
|
||||
buildSearchableOptions(new File(buildContext.projectBuilder.moduleOutput(buildContext.findModule(targetModuleName))), modulesToIndex, pathsToLicenses)
|
||||
buildSearchableOptions(new File(buildContext.projectBuilder.moduleOutput(buildContext.findRequiredModule(targetModuleName))), modulesToIndex, pathsToLicenses)
|
||||
}
|
||||
|
||||
//todo[nik] do we need 'cp' and 'jvmArgs' parameters?
|
||||
@@ -143,6 +143,14 @@ class BuildTasksImpl extends BuildTasks {
|
||||
File originalFile = new File("$buildContext.paths.communityHome/bin/idea.properties")
|
||||
|
||||
String text = originalFile.text
|
||||
if (!buildContext.shouldIDECopyJarsByDefault()) {
|
||||
text += """
|
||||
#---------------------------------------------------------------------
|
||||
# IDE can copy library .jar files to prevent their locking. Set this property to 'false' to enable copying.
|
||||
#---------------------------------------------------------------------
|
||||
idea.jars.nocopy=true
|
||||
"""
|
||||
}
|
||||
buildContext.productProperties.additionalIDEPropertiesFilePaths.each {
|
||||
text += "\n" + new File(it).text
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ class DistributionJARsBuilder {
|
||||
exclude(name: "tips/**")
|
||||
exclude(name: "tips")
|
||||
exclude(name: "search/**")
|
||||
exclude(name: "**/icon-robots.txt")
|
||||
}
|
||||
|
||||
def productLayout = buildContext.productProperties.productLayout
|
||||
@@ -146,7 +147,8 @@ class DistributionJARsBuilder {
|
||||
|
||||
List<String> getPlatformModules() {
|
||||
(platform.moduleJars.values() as List<String>) +
|
||||
["java-runtime" /*required to build searchable options index*/, "updater"]
|
||||
["java-runtime", "platform-main", /*required to build searchable options index*/
|
||||
"updater", buildContext.productProperties.productLayout.mainModule]
|
||||
|
||||
}
|
||||
|
||||
|
||||
+61
-13
@@ -16,8 +16,13 @@
|
||||
package com.intellij.debugger.actions;
|
||||
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.DebuggerUtils;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
|
||||
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
|
||||
import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerSession;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.MethodBytecodeUtil;
|
||||
@@ -36,6 +41,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
import com.intellij.util.Range;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.intellij.util.containers.OrderedSet;
|
||||
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
|
||||
import com.sun.jdi.Location;
|
||||
@@ -68,7 +74,7 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
|
||||
@Override
|
||||
public void threadAction(@NotNull SuspendContextImpl suspendContext) {
|
||||
List<SmartStepTarget> targets = ApplicationManager.getApplication().runReadAction(
|
||||
(Computable<List<SmartStepTarget>>)() -> findSmartStepTargets(position, suspendContext));
|
||||
(Computable<List<SmartStepTarget>>)() -> findSmartStepTargets(position, suspendContext, getDebuggerContext()));
|
||||
DebuggerUIUtil.invokeLater(() -> {
|
||||
if (targets.isEmpty()) {
|
||||
doStepInto(session, Registry.is("debugger.single.smart.step.force"), null);
|
||||
@@ -93,7 +99,9 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
|
||||
throw new IllegalStateException("Should not be used");
|
||||
}
|
||||
|
||||
protected List<SmartStepTarget> findSmartStepTargets(final SourcePosition position, @Nullable SuspendContextImpl suspendContext) {
|
||||
protected List<SmartStepTarget> findSmartStepTargets(final SourcePosition position,
|
||||
@Nullable SuspendContextImpl suspendContext,
|
||||
@NotNull DebuggerContextImpl debuggerContext) {
|
||||
final int line = position.getLine();
|
||||
if (line < 0) {
|
||||
return Collections.emptyList(); // the document has been changed
|
||||
@@ -174,38 +182,78 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
|
||||
|
||||
@Override
|
||||
public void visitField(PsiField field) {
|
||||
TextRange range = field.getTextRange();
|
||||
if (lineRange.intersects(range)) {
|
||||
//textRange.set(textRange.get().union(range));
|
||||
if (checkTextRange(field, false)) {
|
||||
super.visitField(field);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
TextRange range = method.getTextRange();
|
||||
if (lineRange.intersects(range)) {
|
||||
//textRange.set(textRange.get().union(range));
|
||||
if (checkTextRange(method, false)) {
|
||||
super.visitMethod(method);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitStatement(PsiStatement statement) {
|
||||
TextRange range = statement.getTextRange();
|
||||
if (lineRange.intersects(range)) {
|
||||
textRange.set(textRange.get().union(range));
|
||||
if (checkTextRange(statement, true)) {
|
||||
super.visitStatement(statement);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIfStatement(PsiIfStatement statement) {
|
||||
visitConditional(statement.getCondition(), statement.getThenBranch(), statement.getElseBranch());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConditionalExpression(PsiConditionalExpression expression) {
|
||||
visitConditional(expression.getCondition(), expression.getThenExpression(), expression.getElseExpression());
|
||||
}
|
||||
|
||||
private void visitConditional(@Nullable PsiElement condition,
|
||||
@Nullable PsiElement thenBranch,
|
||||
@Nullable PsiElement elseBranch) {
|
||||
if (condition != null) {
|
||||
condition.accept(this);
|
||||
}
|
||||
ThreeState conditionRes = evaluateCondition(condition);
|
||||
if (conditionRes != ThreeState.NO && thenBranch != null) {
|
||||
thenBranch.accept(this);
|
||||
}
|
||||
if (conditionRes != ThreeState.YES && elseBranch != null) {
|
||||
elseBranch.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
private ThreeState evaluateCondition(@Nullable PsiElement condition) {
|
||||
if (condition != null && !DebuggerUtils.hasSideEffects(condition)) {
|
||||
try {
|
||||
ExpressionEvaluator evaluator = EvaluatorBuilderImpl.getInstance().build(condition, position);
|
||||
return ThreeState.fromBoolean(DebuggerUtilsEx.evaluateBoolean(evaluator, debuggerContext.createEvaluationContext()));
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
return ThreeState.UNSURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitExpression(PsiExpression expression) {
|
||||
checkTextRange(expression, true);
|
||||
super.visitExpression(expression);
|
||||
}
|
||||
|
||||
boolean checkTextRange(PsiElement expression, boolean expand) {
|
||||
TextRange range = expression.getTextRange();
|
||||
if (lineRange.intersects(range)) {
|
||||
textRange.set(textRange.get().union(range));
|
||||
if (expand) {
|
||||
textRange.set(textRange.get().union(range));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
super.visitExpression(expression);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void visitExpressionList(PsiExpressionList expressionList) {
|
||||
|
||||
@@ -25,6 +25,8 @@ import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.*;
|
||||
import com.intellij.debugger.engine.evaluation.*;
|
||||
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder;
|
||||
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
|
||||
import com.intellij.debugger.engine.evaluation.expression.UnBoxingEvaluator;
|
||||
import com.intellij.debugger.engine.requests.RequestManagerImpl;
|
||||
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
|
||||
import com.intellij.debugger.requests.Requestor;
|
||||
@@ -865,6 +867,14 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils {
|
||||
return PsiParameter.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
public static boolean evaluateBoolean(ExpressionEvaluator evaluator, EvaluationContextImpl context) throws EvaluateException {
|
||||
Object value = UnBoxingEvaluator.unbox(evaluator.evaluate(context), context);
|
||||
if (!(value instanceof BooleanValue)) {
|
||||
throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected"));
|
||||
}
|
||||
return ((BooleanValue)value).booleanValue();
|
||||
}
|
||||
|
||||
public static boolean intersects(@NotNull TextRange range, @NotNull PsiElement elem) {
|
||||
TextRange elemRange = elem.getTextRange();
|
||||
return elemRange != null && elemRange.intersects(range);
|
||||
|
||||
@@ -25,8 +25,8 @@ import com.intellij.debugger.engine.*;
|
||||
import com.intellij.debugger.engine.evaluation.*;
|
||||
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
|
||||
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
|
||||
import com.intellij.debugger.engine.evaluation.expression.UnBoxingEvaluator;
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.debugger.requests.ClassPrepareRequestor;
|
||||
@@ -371,13 +371,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
return EvaluatorBuilderImpl.build(getCondition(), contextPsiElement, contextSourcePosition, project);
|
||||
}
|
||||
});
|
||||
Object value = UnBoxingEvaluator.unbox(evaluator.evaluate(context), context);
|
||||
if (!(value instanceof BooleanValue)) {
|
||||
throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected"));
|
||||
}
|
||||
if (!((BooleanValue)value).booleanValue()) {
|
||||
return false;
|
||||
}
|
||||
return DebuggerUtilsEx.evaluateBoolean(evaluator, context);
|
||||
}
|
||||
catch (EvaluateException ex) {
|
||||
if (ex.getCause() instanceof VMDisconnectedException) {
|
||||
@@ -387,7 +381,6 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
DebuggerBundle.message("error.failed.evaluating.breakpoint.condition", getCondition(), ex.getMessage())
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException {
|
||||
|
||||
@@ -423,11 +423,14 @@ public abstract class DebuggerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasSideEffects(PsiElement element) {
|
||||
public static boolean hasSideEffects(@Nullable PsiElement element) {
|
||||
return hasSideEffectsOrReferencesMissingVars(element, null);
|
||||
}
|
||||
|
||||
public static boolean hasSideEffectsOrReferencesMissingVars(PsiElement element, @Nullable final Set<String> visibleLocalVariables) {
|
||||
public static boolean hasSideEffectsOrReferencesMissingVars(@Nullable PsiElement element, @Nullable final Set<String> visibleLocalVariables) {
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
final Ref<Boolean> rv = new Ref<>(Boolean.FALSE);
|
||||
element.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
|
||||
@@ -112,7 +112,7 @@ public class JUnitUtil {
|
||||
if (psiMethod.hasModifierProperty(PsiModifier.STATIC) && SUITE_METHOD_NAME.equals(psiMethod.getName())) return false;
|
||||
if (!psiMethod.getName().startsWith("test")) return false;
|
||||
PsiClass testCaseClass = getTestCaseClassOrNull(location);
|
||||
return testCaseClass != null && psiMethod.getContainingClass().isInheritor(testCaseClass, true);
|
||||
return testCaseClass != null && psiMethod.getContainingClass().isInheritor(testCaseClass, true) && PsiType.VOID.equals(psiMethod.getReturnType());
|
||||
}
|
||||
|
||||
public static boolean isTestCaseInheritor(final PsiClass aClass) {
|
||||
|
||||
+4
@@ -33,6 +33,10 @@ public abstract class JavaSourceRootDetector extends ProjectStructureDetector {
|
||||
@Override
|
||||
public DirectoryProcessingResult detectRoots(@NotNull File dir, @NotNull File[] children, @NotNull File base,
|
||||
@NotNull List<DetectedProjectRoot> result) {
|
||||
if (dir.getName().equals("node_modules")) {
|
||||
return DirectoryProcessingResult.SKIP_CHILDREN;
|
||||
}
|
||||
|
||||
final String fileExtension = getFileExtension();
|
||||
for (File child : children) {
|
||||
if (child.isFile() && FileUtilRt.extensionEquals(child.getName(), fileExtension)) {
|
||||
|
||||
+131
@@ -45,6 +45,16 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
private static final String EMPTY_SET_METHOD = "emptySet";
|
||||
private static final String SINGLETON_LIST_METHOD = "singletonList";
|
||||
private static final String SINGLETON_METHOD = "singleton";
|
||||
private static final String COLLECT_METHOD = "collect";
|
||||
|
||||
private static final String COUNTING_COLLECTOR = "counting";
|
||||
private static final String MIN_BY_COLLECTOR = "minBy";
|
||||
private static final String MAX_BY_COLLECTOR = "maxBy";
|
||||
private static final String MAPPING_COLLECTOR = "mapping";
|
||||
private static final String REDUCING_COLLECTOR = "reducing";
|
||||
private static final String SUMMING_INT_COLLECTOR = "summingInt";
|
||||
private static final String SUMMING_LONG_COLLECTOR = "summingLong";
|
||||
private static final String SUMMING_DOUBLE_COLLECTOR = "summingDouble";
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
@@ -95,6 +105,44 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
holder.registerProblem(methodCall, null, fix.getMessage(), fix);
|
||||
}
|
||||
}
|
||||
else if (isCallOf(method, CommonClassNames.JAVA_UTIL_STREAM_STREAM, COLLECT_METHOD, 1)) {
|
||||
PsiElement parameter = methodCall.getArgumentList().getExpressions()[0];
|
||||
if(parameter instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression collectorCall = (PsiMethodCallExpression)parameter;
|
||||
PsiMethod collectorMethod = collectorCall.resolveMethod();
|
||||
ReplaceCollectorFix fix = null;
|
||||
if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, COUNTING_COLLECTOR, 0)) {
|
||||
fix = new ReplaceCollectorFix(COUNTING_COLLECTOR, "count()", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MIN_BY_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(MIN_BY_COLLECTOR, "min({1})", true);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MAX_BY_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(MAX_BY_COLLECTOR, "max({1})", true);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MAPPING_COLLECTOR, 2)) {
|
||||
fix = new ReplaceCollectorFix(MAPPING_COLLECTOR, "map({1}).collect({2})", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "reduce({1})", true);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 2)) {
|
||||
fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "reduce({1}, {2})", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 3)) {
|
||||
fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "map({2}).reduce({1}, {3})", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_INT_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(SUMMING_INT_COLLECTOR, "mapToInt({1}).sum()", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_LONG_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(SUMMING_LONG_COLLECTOR, "mapToLong({1}).sum()", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_DOUBLE_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(SUMMING_DOUBLE_COLLECTOR, "mapToDouble({1}).sum()", false);
|
||||
}
|
||||
if (fix != null &&
|
||||
collectorCall.getArgumentList().getExpressions().length == collectorMethod.getParameterList().getParametersCount()) {
|
||||
TextRange range = methodCall.getTextRange();
|
||||
PsiElement nameElement = methodCall.getMethodExpression().getReferenceNameElement();
|
||||
if(nameElement != null) {
|
||||
range = new TextRange(nameElement.getTextOffset(), range.getEndOffset());
|
||||
}
|
||||
holder.registerProblem(methodCall, range.shiftRight(-methodCall.getTextOffset()), fix.getMessage(), fix);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
final String name;
|
||||
if (isCallOf(method, CommonClassNames.JAVA_UTIL_STREAM_STREAM, FOR_EACH_METHOD, 1)) {
|
||||
@@ -390,4 +438,87 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReplaceCollectorFix implements LocalQuickFix {
|
||||
private final String myCollector;
|
||||
private final String myStreamSequence;
|
||||
private final String myStreamSequenceStripped;
|
||||
private final boolean myChangeSemantics;
|
||||
|
||||
public ReplaceCollectorFix(String collector, String streamSequence, boolean changeSemantics) {
|
||||
myCollector = collector;
|
||||
myStreamSequence = streamSequence;
|
||||
myStreamSequenceStripped = streamSequence.replaceAll("\\([^)]+\\)", "()");
|
||||
myChangeSemantics = changeSemantics;
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Replace Stream.collect(" + myCollector +
|
||||
"()) with Stream." + myStreamSequenceStripped +
|
||||
(myChangeSemantics ? " (may change semantics when result is null)" : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement element = descriptor.getStartElement();
|
||||
if (element instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression collectCall = (PsiMethodCallExpression)element;
|
||||
PsiExpression qualifierExpression = collectCall.getMethodExpression().getQualifierExpression();
|
||||
if (qualifierExpression != null) {
|
||||
PsiElement parameter = collectCall.getArgumentList().getExpressions()[0];
|
||||
if (parameter instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression collectorCall = (PsiMethodCallExpression)parameter;
|
||||
PsiExpression[] collectorArgs = collectorCall.getArgumentList().getExpressions();
|
||||
String result = myStreamSequence;
|
||||
for(int i=0; i<collectorArgs.length; i++) {
|
||||
result = result.replace("{"+(i+1)+"}", collectorArgs[i].getText());
|
||||
}
|
||||
if (!FileModificationService.getInstance().preparePsiElementForWrite(element.getContainingFile())) return;
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
PsiExpression replacement = factory.createExpressionFromText(
|
||||
qualifierExpression.getText() + "." + result, collectCall);
|
||||
PsiElement expression = collectCall.replace(replacement);
|
||||
// Replacements like .collect(counting()) -> .count() change the result type from boxed to primitive
|
||||
// In rare cases it's necessary to add cast to return back to boxed type
|
||||
// example:
|
||||
// List<Integer> intList; List<String> stringList;
|
||||
// intList.remove(stringList.stream().collect(summingInt(String::length)) -- remove given element
|
||||
// intList.remove(stringList.stream().mapToInt(String::length).sum()) -- remove element by index
|
||||
if(expression instanceof PsiExpression) {
|
||||
PsiType type = ((PsiExpression)expression).getType();
|
||||
if(type instanceof PsiPrimitiveType) {
|
||||
PsiClassType boxedType = ((PsiPrimitiveType)type).getBoxedType(expression);
|
||||
if(boxedType != null) {
|
||||
PsiExpression castExpression =
|
||||
factory.createExpressionFromText("(" + boxedType.getCanonicalText() + ") " + expression.getText(), expression);
|
||||
PsiElement cast = expression.replace(castExpression);
|
||||
if (cast instanceof PsiTypeCastExpression && RedundantCastUtil.isCastRedundant((PsiTypeCastExpression)cast)) {
|
||||
RedundantCastUtil.removeCast((PsiTypeCastExpression)cast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
String getMessage() {
|
||||
return "Stream.collect(" + myCollector +
|
||||
"()) can be replaced with Stream." + myStreamSequenceStripped + "()" +
|
||||
(myChangeSemantics ? " (may change semantics when result is null)" : "");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -126,13 +126,8 @@ public class AllClassesGetter {
|
||||
public static final InsertHandler<JavaPsiClassReferenceElement> INSERT_FQN = (context, item) -> {
|
||||
final String qName = item.getQualifiedName();
|
||||
if (qName != null) {
|
||||
int start = context.getTailOffset() - 1;
|
||||
while (start >= 0) {
|
||||
final char ch = context.getDocument().getCharsSequence().charAt(start);
|
||||
if (!Character.isJavaIdentifierPart(ch) && ch != '.') break;
|
||||
start--;
|
||||
}
|
||||
context.getDocument().replaceString(start + 1, context.getTailOffset(), qName);
|
||||
int start = JavaCompletionUtil.findQualifiedNameStart(context);
|
||||
context.getDocument().replaceString(start, context.getTailOffset(), qName);
|
||||
LOG.assertTrue(context.getTailOffset() >= 0);
|
||||
}
|
||||
};
|
||||
|
||||
+6
-1
@@ -7,7 +7,10 @@ import com.intellij.codeInsight.generation.OverrideImplementExploreUtil;
|
||||
import com.intellij.codeInsight.generation.OverrideImplementUtil;
|
||||
import com.intellij.codeInsight.generation.PsiGenerationInfo;
|
||||
import com.intellij.codeInsight.intention.impl.TypeExpression;
|
||||
import com.intellij.codeInsight.lookup.*;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator;
|
||||
import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
|
||||
import com.intellij.codeInsight.template.*;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
@@ -260,6 +263,8 @@ public class ConstructorInsertHandler implements InsertHandler<LookupElementDeco
|
||||
|
||||
private static Runnable createOverrideRunnable(final Editor editor, final PsiFile file, final Project project) {
|
||||
return () -> {
|
||||
TemplateManager.getInstance(project).finishTemplate(editor);
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
final PsiAnonymousClass
|
||||
aClass = PsiTreeUtil.findElementOfClassAtOffset(file, editor.getCaretModel().getOffset(), PsiAnonymousClass.class, false);
|
||||
|
||||
+7
-8
@@ -16,7 +16,6 @@
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.AutoPopupController;
|
||||
import com.intellij.codeInsight.ExpectedTypeInfo;
|
||||
import com.intellij.codeInsight.ExpectedTypesProvider;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
@@ -34,6 +33,7 @@ import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.javadoc.PsiDocTag;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.codeStyle.JavaCodeStyleSettings.*;
|
||||
@@ -159,18 +159,17 @@ class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceE
|
||||
|
||||
final PsiElement prevElement = FilterPositionUtil.searchNonSpaceNonCommentBack(ref);
|
||||
if (prevElement != null && prevElement.getParent() instanceof PsiNewExpression) {
|
||||
for (ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes((PsiExpression)prevElement.getParent(), true)) {
|
||||
if (info.getType() instanceof PsiArrayType) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return !isArrayTypeExpected((PsiExpression)prevElement.getParent());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean isArrayTypeExpected(PsiExpression expr) {
|
||||
return ContainerUtil.exists(ExpectedTypesProvider.getExpectedTypes(expr, true),
|
||||
info -> info.getType() instanceof PsiArrayType);
|
||||
}
|
||||
|
||||
private static boolean insertingAnnotation(InsertionContext context, LookupElement item) {
|
||||
final Object obj = item.getObject();
|
||||
if (!(obj instanceof PsiClass) || !((PsiClass)obj).isAnnotationType()) return false;
|
||||
|
||||
+2
-6
@@ -226,12 +226,8 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
PrefixMatcher matcher = result.getPrefixMatcher();
|
||||
PsiElement parent = position.getParent();
|
||||
|
||||
if (JavaModuleCompletion.isModuleFile(position.getContainingFile())) {
|
||||
JavaModuleCompletion.addVariants(position, element -> {
|
||||
if (element.getLookupString().startsWith(result.getPrefixMatcher().getPrefix())) {
|
||||
result.addElement(element);
|
||||
}
|
||||
});
|
||||
if (JavaModuleCompletion.isModuleFile(parameters.getOriginalFile())) {
|
||||
JavaModuleCompletion.addVariants(position, result);
|
||||
result.stopHere();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -528,10 +528,7 @@ public class JavaCompletionUtil {
|
||||
.accepts(reference),
|
||||
JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER,
|
||||
Conditions.alwaysTrue());
|
||||
if (JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference)) {
|
||||
return JBIterable.from(classItems).flatMap(i -> JavaConstructorCallElement.wrap(i, reference.getElement()));
|
||||
}
|
||||
return classItems;
|
||||
return JBIterable.from(classItems).flatMap(i -> JavaConstructorCallElement.wrap(i, reference.getElement()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,11 +541,7 @@ public class JavaCompletionUtil {
|
||||
if (completion instanceof PsiClass) {
|
||||
JavaPsiClassReferenceElement classItem =
|
||||
JavaClassNameCompletionContributor.createClassLookupItem((PsiClass)completion, true).setSubstitutor(substitutor);
|
||||
if (JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference)) {
|
||||
return JavaConstructorCallElement.wrap(classItem, reference.getElement());
|
||||
}
|
||||
|
||||
return Collections.singletonList(classItem);
|
||||
return JavaConstructorCallElement.wrap(classItem, reference.getElement());
|
||||
}
|
||||
if (completion instanceof PsiMethod) {
|
||||
JavaMethodCallElement item = new JavaMethodCallElement((PsiMethod)completion).setQualifierSubstitutor(substitutor);
|
||||
@@ -935,4 +928,14 @@ public class JavaCompletionUtil {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static int findQualifiedNameStart(@NotNull InsertionContext context) {
|
||||
int start = context.getTailOffset() - 1;
|
||||
while (start >= 0) {
|
||||
char ch = context.getDocument().getCharsSequence().charAt(start);
|
||||
if (!Character.isJavaIdentifierPart(ch) && ch != '.') break;
|
||||
start--;
|
||||
}
|
||||
return start + 1;
|
||||
}
|
||||
}
|
||||
+27
-6
@@ -20,7 +20,11 @@ import com.intellij.codeInsight.lookup.LookupElementDecorator;
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.JBIterable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -42,6 +46,10 @@ public class JavaConstructorCallElement extends JavaMethodCallElement {
|
||||
myType = type.get();
|
||||
setQualifierSubstitutor(myType.resolveGenerics().getSubstitutor());
|
||||
|
||||
markClassItemWrapped(classItem);
|
||||
}
|
||||
|
||||
private void markClassItemWrapped(@NotNull LookupElement classItem) {
|
||||
LookupElement delegate = classItem;
|
||||
while (true) {
|
||||
delegate.putUserData(WRAPPING_CONSTRUCTOR_CALL, this);
|
||||
@@ -65,19 +73,24 @@ public class JavaConstructorCallElement extends JavaMethodCallElement {
|
||||
@Override
|
||||
public void renderElement(LookupElementPresentation presentation) {
|
||||
myClassItem.renderElement(presentation);
|
||||
String itemText = presentation.getItemText();
|
||||
|
||||
super.renderElement(presentation);
|
||||
presentation.setItemText(itemText);
|
||||
String tailText = StringUtil.notNullize(presentation.getTailText());
|
||||
int genericsEnd = tailText.lastIndexOf('>') + 1;
|
||||
|
||||
presentation.clearTail();
|
||||
presentation.appendTailText(tailText.substring(0, genericsEnd), false);
|
||||
presentation.appendTailText(MemberLookupHelper.getMethodParameterString(getObject(), getSubstitutor()), false);
|
||||
presentation.appendTailText(tailText.substring(genericsEnd), true);
|
||||
}
|
||||
|
||||
static List<? extends LookupElement> wrap(JavaPsiClassReferenceElement classItem, PsiElement position) {
|
||||
static List<? extends LookupElement> wrap(@NotNull JavaPsiClassReferenceElement classItem, @NotNull PsiElement position) {
|
||||
PsiClass psiClass = classItem.getObject();
|
||||
return wrap(classItem, psiClass, position, () -> JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, PsiSubstitutor.EMPTY));
|
||||
}
|
||||
|
||||
static List<? extends LookupElement> wrap(LookupElement classItem, PsiClass psiClass, PsiElement position, Supplier<PsiClassType> type) {
|
||||
if (Registry.is("java.completion.show.constructors") && JavaClassNameCompletionContributor.AFTER_NEW.accepts(position)) {
|
||||
static List<? extends LookupElement> wrap(@NotNull LookupElement classItem, @NotNull PsiClass psiClass,
|
||||
@NotNull PsiElement position, @NotNull Supplier<PsiClassType> type) {
|
||||
if (Registry.is("java.completion.show.constructors") && isConstructorCallPlace(position)) {
|
||||
PsiMethod[] constructors = psiClass.getConstructors();
|
||||
if (constructors.length > 0) {
|
||||
return JBIterable.of(constructors).
|
||||
@@ -89,6 +102,14 @@ public class JavaConstructorCallElement extends JavaMethodCallElement {
|
||||
return Collections.singletonList(classItem);
|
||||
}
|
||||
|
||||
private static boolean isConstructorCallPlace(@NotNull PsiElement position) {
|
||||
return CachedValuesManager.getCachedValue(position, () -> {
|
||||
boolean result = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position) &&
|
||||
!JavaClassNameInsertHandler.isArrayTypeExpected(PsiTreeUtil.getParentOfType(position, PsiNewExpression.class));
|
||||
return CachedValueProvider.Result.create(result, position);
|
||||
});
|
||||
}
|
||||
|
||||
static boolean isWrapped(LookupElement element) {
|
||||
return element.getUserData(WRAPPING_CONSTRUCTOR_CALL) != null;
|
||||
}
|
||||
|
||||
@@ -22,10 +22,15 @@ import com.intellij.codeInsight.template.Template;
|
||||
import com.intellij.codeInsight.template.TemplateManager;
|
||||
import com.intellij.codeInsight.template.impl.ConstantNode;
|
||||
import com.intellij.codeInsight.template.impl.MacroCallNode;
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateState;
|
||||
import com.intellij.codeInsight.template.macro.CompleteMacro;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.ClassConditionKey;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
@@ -170,7 +175,7 @@ public class JavaMethodCallElement extends LookupItem<PsiMethod> implements Type
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParams && Registry.is("java.completion.argument.live.template")) {
|
||||
if (hasParams && context.getCompletionChar() != Lookup.COMPLETE_STATEMENT_SELECT_CHAR && Registry.is("java.completion.argument.live.template")) {
|
||||
startArgumentLiveTemplate(context, method);
|
||||
}
|
||||
}
|
||||
@@ -187,7 +192,8 @@ public class JavaMethodCallElement extends LookupItem<PsiMethod> implements Type
|
||||
qualifyMethodCall(file, startOffset, document);
|
||||
}
|
||||
|
||||
private static void startArgumentLiveTemplate(InsertionContext context, PsiMethod method) {
|
||||
public static final Key<JavaMethodCallElement> ARGUMENT_TEMPLATE_ACTIVE = Key.create("ARGUMENT_TEMPLATE_ACTIVE");
|
||||
private void startArgumentLiveTemplate(InsertionContext context, PsiMethod method) {
|
||||
TemplateManager manager = TemplateManager.getInstance(method.getProject());
|
||||
Template template = manager.createTemplate("", "");
|
||||
PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
@@ -199,7 +205,18 @@ public class JavaMethodCallElement extends LookupItem<PsiMethod> implements Type
|
||||
template.addVariable(name, new MacroCallNode(new CompleteMacro()), new ConstantNode(name), true);
|
||||
}
|
||||
|
||||
manager.startTemplate(context.getEditor(), template);
|
||||
Editor editor = context.getEditor();
|
||||
manager.startTemplate(editor, template);
|
||||
|
||||
TemplateState templateState = TemplateManagerImpl.getTemplateState(editor);
|
||||
if (templateState == null) return;
|
||||
|
||||
editor.putUserData(ARGUMENT_TEMPLATE_ACTIVE, this);
|
||||
Disposer.register(templateState, () -> {
|
||||
if (editor.getUserData(ARGUMENT_TEMPLATE_ACTIVE) == this) {
|
||||
editor.putUserData(ARGUMENT_TEMPLATE_ACTIVE, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean shouldInsertTypeParameters() {
|
||||
|
||||
@@ -19,21 +19,22 @@ import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.completion.JavaKeywordCompletion.OverrideableSpace;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.module.impl.scopes.ModulesScope;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.file.impl.JavaFileManager;
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaModuleNameIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.ProjectScope;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static com.intellij.codeInsight.completion.JavaKeywordCompletion.createKeyword;
|
||||
|
||||
class JavaModuleCompletion {
|
||||
@@ -41,7 +42,13 @@ class JavaModuleCompletion {
|
||||
return PsiUtil.isLanguageLevel9OrHigher(file) && PsiJavaModule.MODULE_INFO_FILE.equals(file.getName());
|
||||
}
|
||||
|
||||
static void addVariants(@NotNull PsiElement position, @NotNull Consumer<LookupElement> result) {
|
||||
static void addVariants(@NotNull PsiElement position, @NotNull CompletionResultSet resultSet) {
|
||||
Consumer<LookupElement> result = element -> {
|
||||
if (element.getLookupString().startsWith(resultSet.getPrefixMatcher().getPrefix())) {
|
||||
resultSet.addElement(element);
|
||||
}
|
||||
};
|
||||
|
||||
if (position instanceof PsiIdentifier) {
|
||||
PsiElement context = position.getParent();
|
||||
if (context instanceof PsiErrorElement) context = context.getParent();
|
||||
@@ -52,11 +59,14 @@ class JavaModuleCompletion {
|
||||
else if (context instanceof PsiJavaModule) {
|
||||
addModuleStatementKeywords(position, result);
|
||||
}
|
||||
else if (context instanceof PsiProvidesStatement) {
|
||||
addProvidesStatementKeywords(position, result);
|
||||
}
|
||||
else if (context instanceof PsiJavaModuleReferenceElement) {
|
||||
addModuleReferences(context, result);
|
||||
}
|
||||
else if (context instanceof PsiJavaCodeReferenceElement) {
|
||||
addCodeReferences(context, result);
|
||||
addCodeReferences(context, result, resultSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +84,10 @@ class JavaModuleCompletion {
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.PROVIDES), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
}
|
||||
|
||||
private static void addProvidesStatementKeywords(PsiElement position, Consumer<LookupElement> result) {
|
||||
result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.WITH), TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
}
|
||||
|
||||
private static void addModuleReferences(PsiElement context, Consumer<LookupElement> result) {
|
||||
PsiJavaModule host = PsiTreeUtil.getParentOfType(context, PsiJavaModule.class);
|
||||
if (host != null) {
|
||||
@@ -90,24 +104,81 @@ class JavaModuleCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
private static void addCodeReferences(PsiElement context, Consumer<LookupElement> result) {
|
||||
PsiElement statement = PsiTreeUtil.skipParentsOfType(context, PsiJavaCodeReferenceElement.class);
|
||||
private static void addCodeReferences(PsiElement context, Consumer<LookupElement> result, CompletionResultSet resultSet) {
|
||||
PsiElement statement = context.getParent();
|
||||
if (statement instanceof PsiExportsStatement) {
|
||||
Module module = ModuleUtilCore.findModuleForPsiElement(context);
|
||||
PsiPackage topPackage = ServiceManager.getService(context.getProject(), JavaFileManager.class).findPackage("");
|
||||
PsiPackage topPackage = JavaPsiFacade.getInstance(context.getProject()).findPackage("");
|
||||
if (module != null && topPackage != null) {
|
||||
processPackage(topPackage, new ModulesScope(module), result);
|
||||
}
|
||||
}
|
||||
else if (statement instanceof PsiUsesStatement) {
|
||||
processClasses(context.getProject(), null, resultSet, SERVICE_FILTER, TailType.SEMICOLON);
|
||||
}
|
||||
else if (statement instanceof PsiProvidesStatement) {
|
||||
PsiJavaCodeReferenceElement intRef = ((PsiProvidesStatement)statement).getInterfaceReference();
|
||||
if (context == intRef) {
|
||||
processClasses(context.getProject(), null, resultSet, SERVICE_FILTER, TailType.HUMBLE_SPACE_BEFORE_WORD);
|
||||
}
|
||||
else if (context == ((PsiProvidesStatement)statement).getImplementationReference() && intRef != null) {
|
||||
PsiElement service = intRef.resolve();
|
||||
Module module = ModuleUtilCore.findModuleForPsiElement(context);
|
||||
if (service instanceof PsiClass && module != null) {
|
||||
Predicate<PsiClass> filter = psiClass -> !psiClass.hasModifierProperty(PsiModifier.ABSTRACT) &&
|
||||
InheritanceUtil.isInheritorOrSelf(psiClass, (PsiClass)service, true);
|
||||
processClasses(context.getProject(), new ModulesScope(module), resultSet, filter, TailType.SEMICOLON);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processPackage(PsiPackage pkg, ModulesScope scope, Consumer<LookupElement> result) {
|
||||
String packageName = pkg.getQualifiedName();
|
||||
if (packageName.indexOf('.') > 0 && !PsiUtil.isPackageEmpty(pkg.getDirectories(scope), packageName)) {
|
||||
result.consume(new OverrideableSpace(LookupElementBuilder.create(packageName), TailType.SEMICOLON));
|
||||
if (isQualified(packageName) && !PsiUtil.isPackageEmpty(pkg.getDirectories(scope), packageName)) {
|
||||
result.consume(new OverrideableSpace(lookupElement(pkg), TailType.SEMICOLON));
|
||||
}
|
||||
for (PsiPackage subPackage : pkg.getSubPackages(scope)) {
|
||||
processPackage(subPackage, scope, result);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Predicate<PsiClass> SERVICE_FILTER =
|
||||
psiClass -> !psiClass.isEnum() && psiClass.hasModifierProperty(PsiModifier.PUBLIC);
|
||||
|
||||
private static void processClasses(Project project,
|
||||
GlobalSearchScope scope,
|
||||
CompletionResultSet resultSet,
|
||||
Predicate<PsiClass> filter,
|
||||
TailType tail) {
|
||||
GlobalSearchScope _scope = scope != null ? scope : ProjectScope.getAllScope(project);
|
||||
AllClassesGetter.processJavaClasses(resultSet.getPrefixMatcher(), project, _scope, psiClass -> {
|
||||
if (isQualified(psiClass.getQualifiedName()) && filter.test(psiClass)) {
|
||||
resultSet.addElement(new OverrideableSpace(lookupElement(psiClass), tail));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private static LookupElementBuilder lookupElement(PsiNamedElement e) {
|
||||
LookupElementBuilder lookup = LookupElementBuilder.create(e).withInsertHandler(FQN_INSERT_HANDLER);
|
||||
String fqn = e instanceof PsiClass ? ((PsiClass)e).getQualifiedName() : ((PsiQualifiedNamedElement)e).getQualifiedName();
|
||||
return fqn != null ? lookup.withPresentableText(fqn) : lookup;
|
||||
}
|
||||
|
||||
private static boolean isQualified(String name) {
|
||||
return name != null && name.indexOf('.') > 0;
|
||||
}
|
||||
|
||||
private static final InsertHandler<LookupElement> FQN_INSERT_HANDLER = new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
Object e = item.getObject();
|
||||
String fqn = e instanceof PsiClass ? ((PsiClass)e).getQualifiedName() : ((PsiQualifiedNamedElement)e).getQualifiedName();
|
||||
if (fqn != null) {
|
||||
int start = JavaCompletionUtil.findQualifiedNameStart(context);
|
||||
context.getDocument().replaceString(start, context.getTailOffset(), fqn);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,10 @@ import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
public class JavaNoVariantsDelegator extends CompletionContributor {
|
||||
@Override
|
||||
public void fillCompletionVariants(@NotNull final CompletionParameters parameters, @NotNull final CompletionResultSet result) {
|
||||
if (JavaModuleCompletion.isModuleFile(parameters.getOriginalFile())) {
|
||||
return;
|
||||
}
|
||||
|
||||
final JavaCompletionSession session = new JavaCompletionSession(result);
|
||||
ResultTracker tracker = new ResultTracker(result) {
|
||||
@Override
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtilBase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
@@ -78,9 +79,7 @@ public class MemberLookupHelper {
|
||||
final String params = myMergedOverloads
|
||||
? "(...)"
|
||||
: myMember instanceof PsiMethod
|
||||
? PsiFormatUtil.formatMethod((PsiMethod)myMember, substitutor,
|
||||
PsiFormatUtilBase.SHOW_PARAMETERS,
|
||||
PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_TYPE)
|
||||
? getMethodParameterString((PsiMethod)myMember, substitutor)
|
||||
: "";
|
||||
presentation.clearTail();
|
||||
presentation.appendTailText(params, false);
|
||||
@@ -96,5 +95,9 @@ public class MemberLookupHelper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
static String getMethodParameterString(@NotNull PsiMethod method, @NotNull PsiSubstitutor substitutor) {
|
||||
return PsiFormatUtil.formatMethod(method, substitutor,
|
||||
PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -16,10 +16,13 @@
|
||||
package com.intellij.codeInsight.template.macro;
|
||||
|
||||
import com.intellij.codeInsight.completion.JavaCompletionUtil;
|
||||
import com.intellij.codeInsight.completion.JavaMethodCallElement;
|
||||
import com.intellij.codeInsight.completion.SmartCompletionDecorator;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.template.ExpressionContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.ClassConditionKey;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiPackage;
|
||||
|
||||
import java.util.List;
|
||||
@@ -34,6 +37,12 @@ public class JavaTemplateCompletionProcessor implements TemplateCompletionProces
|
||||
if (elements != null && elements.size() == 1 && elements.get(0) instanceof PsiPackage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Editor editor = context.getEditor();
|
||||
if (editor != null && editor.getUserData(JavaMethodCallElement.ARGUMENT_TEMPLATE_ACTIVE) != null) {
|
||||
return item.as(ClassConditionKey.create(SmartCompletionDecorator.class)) != null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.deadCode;
|
||||
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.GlobalJavaInspectionContext;
|
||||
import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.codeInspection.ex.*;
|
||||
@@ -24,6 +23,7 @@ import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.reference.RefJavaElement;
|
||||
import com.intellij.codeInspection.ui.InspectionNode;
|
||||
import com.intellij.codeInspection.ui.InspectionResultsView;
|
||||
import com.intellij.codeInspection.ui.InspectionTree;
|
||||
import com.intellij.codeInspection.ui.InspectionTreeNode;
|
||||
import com.intellij.codeInspection.util.RefFilter;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
@@ -43,7 +43,7 @@ public class DummyEntryPointsPresentation extends UnusedDeclarationPresentation
|
||||
}
|
||||
|
||||
@Override
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) {
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, InspectionTree tree) {
|
||||
if (myQuickFixActions == null) {
|
||||
myQuickFixActions = new QuickFixAction[]{new MoveEntriesToSuspicious(getToolWrapper())};
|
||||
}
|
||||
|
||||
+19
-3
@@ -67,6 +67,7 @@ import javax.swing.text.html.HTML;
|
||||
import javax.swing.text.html.HTMLDocument;
|
||||
import javax.swing.text.html.HTMLEditorKit;
|
||||
import javax.swing.text.html.StyleSheet;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -182,7 +183,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
}
|
||||
|
||||
@Override
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) {
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, InspectionTree tree) {
|
||||
boolean showFixes = false;
|
||||
for (RefEntity element : refElements) {
|
||||
if (!getIgnoredRefElements().contains(element) && element.isValid()) {
|
||||
@@ -192,8 +193,23 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
}
|
||||
|
||||
if (showFixes) {
|
||||
final QuickFixAction[] fixes = super.getQuickFixes(refElements, allowedDescriptors);
|
||||
return fixes != null ? ArrayUtil.mergeArrays(fixes, myQuickFixActions) : myQuickFixActions;
|
||||
final TreePath[] paths = tree.getSelectionPaths();
|
||||
if (paths != null) {
|
||||
int count = 0;
|
||||
for (TreePath path : paths) {
|
||||
final Object component = path.getLastPathComponent();
|
||||
if (component instanceof ProblemDescriptionNode) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
final QuickFixAction[] fixes = super.getQuickFixes(refElements, tree);
|
||||
if (fixes != null) {
|
||||
return count == paths.length ? fixes : ArrayUtil.mergeArrays(fixes, myQuickFixActions);
|
||||
}
|
||||
}
|
||||
}
|
||||
return myQuickFixActions;
|
||||
}
|
||||
return QuickFixAction.EMPTY;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.Inlay
|
||||
import com.intellij.openapi.project.Project
|
||||
@@ -35,6 +36,10 @@ class ReportMissingOrExcessiveInlineHint : AnAction() {
|
||||
private val text = "Report Missing or Excessive Inline Hint"
|
||||
private val description = "Text line at caret will be anonymously reported to our servers"
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(ReportMissingOrExcessiveInlineHint::class.java)
|
||||
}
|
||||
|
||||
init {
|
||||
val presentation = templatePresentation
|
||||
presentation.text = text
|
||||
@@ -85,12 +90,14 @@ class ReportMissingOrExcessiveInlineHint : AnAction() {
|
||||
}
|
||||
|
||||
private fun trySendFileInBackground() {
|
||||
LOG.debug("File: ${file.path} Length: ${file.length()}")
|
||||
if (!file.exists() || file.length() == 0L) return
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread {
|
||||
val text = file.readText()
|
||||
LOG.debug("File text $text")
|
||||
if (StatsSender.send(text)) {
|
||||
file.delete()
|
||||
LOG.debug("File deleted")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-13
@@ -63,9 +63,10 @@ class ConstructorReferencesSearchHelper {
|
||||
DumbService.getInstance(project).runReadActionInSmartMode(new Computable<Void>() {
|
||||
@Override
|
||||
public Void compute() {
|
||||
constructorCanBeCalledImplicitly[0] = constructor.getParameterList().getParametersCount() == 0;
|
||||
final PsiParameter[] parameters = constructor.getParameterList().getParameters();
|
||||
constructorCanBeCalledImplicitly[0] = parameters.length == 0;
|
||||
if (!constructorCanBeCalledImplicitly[0]) {
|
||||
constructorCanBeCalledImplicitly[0] = hasDefaultConstructorWithVarargParameter(containingClass);
|
||||
constructorCanBeCalledImplicitly[0] = parameters.length == 1 && parameters[0].isVarArgs();
|
||||
}
|
||||
isEnum[0] = containingClass.isEnum();
|
||||
isUnder18[0] = PsiUtil.getLanguageLevel(containingClass).isAtLeast(LanguageLevel.JDK_1_8);
|
||||
@@ -127,17 +128,6 @@ class ConstructorReferencesSearchHelper {
|
||||
return ClassInheritorsSearch.search(containingClass, searchScope, false).forEach(processor2);
|
||||
}
|
||||
|
||||
private static boolean hasDefaultConstructorWithVarargParameter(@NotNull PsiClass containingClass) {
|
||||
final PsiMethod[] constructors = containingClass.getConstructors();
|
||||
for (PsiMethod ctr : constructors) {
|
||||
final PsiParameter[] parameters = ctr.getParameterList().getParameters();
|
||||
if (parameters.length == 1 && parameters[0].isVarArgs()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean processEnumReferences(@NotNull final Processor<PsiReference> processor,
|
||||
@NotNull final PsiMethod constructor,
|
||||
@NotNull final Project project,
|
||||
|
||||
@@ -21,13 +21,19 @@ import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiKeyword;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static com.intellij.lang.PsiBuilderUtil.expect;
|
||||
import static com.intellij.lang.java.parser.JavaParserUtil.error;
|
||||
import static com.intellij.lang.java.parser.JavaParserUtil.semicolon;
|
||||
|
||||
public class ModuleParser {
|
||||
private static final Set<String> STATEMENT_KEYWORDS =
|
||||
ContainerUtil.newHashSet(PsiKeyword.REQUIRES, PsiKeyword.EXPORTS, PsiKeyword.USES, PsiKeyword.PROVIDES);
|
||||
|
||||
public static void parseModule(@NotNull PsiBuilder builder) {
|
||||
PsiBuilder.Marker module = builder.mark();
|
||||
mapAndAdvance(builder, JavaTokenType.MODULE_KEYWORD);
|
||||
@@ -225,7 +231,15 @@ public class ModuleParser {
|
||||
}
|
||||
}
|
||||
else if (!hasError) {
|
||||
error(builder, JavaErrorMessages.message("expected.with"));
|
||||
IElementType next = builder.getTokenType();
|
||||
if (next == JavaTokenType.IDENTIFIER && !STATEMENT_KEYWORDS.contains(builder.getTokenText())) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
builder.advanceLexer();
|
||||
marker.error(JavaErrorMessages.message("expected.with"));
|
||||
}
|
||||
else {
|
||||
error(builder, JavaErrorMessages.message("expected.with"));
|
||||
}
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
|
||||
import com.intellij.psi.impl.java.stubs.PsiClassStub;
|
||||
import com.intellij.psi.impl.source.tree.ChildRole;
|
||||
import com.intellij.psi.impl.source.tree.SharedImplUtil;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.reference.SoftReference;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
@@ -66,7 +65,7 @@ public class PsiAnonymousClassImpl extends PsiClassImpl implements PsiAnonymousC
|
||||
@Override
|
||||
@NotNull
|
||||
public PsiClassType getBaseClassType() {
|
||||
final PsiClassStub stub = getStub();
|
||||
final PsiClassStub stub = getGreenStub();
|
||||
if (stub == null) {
|
||||
myCachedBaseType = null;
|
||||
return getTypeByTree();
|
||||
@@ -192,7 +191,7 @@ public class PsiAnonymousClassImpl extends PsiClassImpl implements PsiAnonymousC
|
||||
|
||||
@Override
|
||||
public boolean isInQualifiedNew() {
|
||||
final PsiClassStub stub = getStub();
|
||||
final PsiClassStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.isAnonymousInQualifiedNew();
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiClass getContainingClass() {
|
||||
final PsiClassStub stub = getStub();
|
||||
final PsiClassStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
StubElement parent = stub.getParentStub();
|
||||
return parent instanceof PsiClassStub ? ((PsiClassStub<?>)parent).getPsi() : null;
|
||||
@@ -540,7 +540,7 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements
|
||||
private static boolean isAnonymousOrLocal(PsiClass aClass) {
|
||||
if (aClass instanceof PsiAnonymousClass) return true;
|
||||
|
||||
final PsiClassStub stub = ((PsiClassImpl)aClass).getStub();
|
||||
final PsiClassStub stub = ((PsiClassImpl)aClass).getGreenStub();
|
||||
if (stub != null) {
|
||||
final StubElement parentStub = stub.getParentStub();
|
||||
return !(parentStub instanceof PsiClassStub || parentStub instanceof PsiFileStub);
|
||||
|
||||
@@ -174,7 +174,7 @@ public class PsiEnumConstantImpl extends JavaStubPsiElement<PsiFieldStub> implem
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
final PsiFieldStub stub = getStub();
|
||||
final PsiFieldStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getName();
|
||||
}
|
||||
@@ -194,7 +194,7 @@ public class PsiEnumConstantImpl extends JavaStubPsiElement<PsiFieldStub> implem
|
||||
|
||||
@Override
|
||||
public boolean isDeprecated() {
|
||||
final PsiFieldStub stub = getStub();
|
||||
final PsiFieldStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.isDeprecated();
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
final PsiFieldStub stub = getStub();
|
||||
final PsiFieldStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getName();
|
||||
}
|
||||
@@ -185,7 +185,7 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps
|
||||
private PsiField findFirstFieldInDeclaration() {
|
||||
if (getSelfModifierList() != null) return this;
|
||||
|
||||
final PsiFieldStub stub = getStub();
|
||||
final PsiFieldStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
final List siblings = stub.getParentStub().getChildrenStubs();
|
||||
final int idx = siblings.indexOf(stub);
|
||||
@@ -226,7 +226,7 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps
|
||||
// avoids stub-to-AST switch if possible,
|
||||
// returns the light generated initializer literal expression if stored in stubs, the regular initializer if wasn't
|
||||
public PsiExpression getDetachedInitializer() {
|
||||
final PsiFieldStub stub = getStub();
|
||||
final PsiFieldStub stub = getGreenStub();
|
||||
PsiExpression initializer;
|
||||
if (stub == null) {
|
||||
initializer = getInitializer();
|
||||
@@ -251,7 +251,7 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps
|
||||
|
||||
@Override
|
||||
public boolean hasInitializer() {
|
||||
PsiFieldStub stub = getStub();
|
||||
PsiFieldStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getInitializerText() != null;
|
||||
}
|
||||
@@ -299,7 +299,7 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps
|
||||
|
||||
@Override
|
||||
public boolean isDeprecated() {
|
||||
final PsiFieldStub stub = getStub();
|
||||
final PsiFieldStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.isDeprecated() || stub.hasDeprecatedAnnotation() && PsiImplUtil.isDeprecatedByAnnotation(this);
|
||||
}
|
||||
@@ -309,7 +309,7 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps
|
||||
|
||||
@Override
|
||||
public PsiDocComment getDocComment(){
|
||||
final PsiFieldStub stub = getStub();
|
||||
final PsiFieldStub stub = getGreenStub();
|
||||
if (stub != null && !stub.hasDocComment()) return null;
|
||||
|
||||
CompositeElement treeElement = getNode();
|
||||
|
||||
@@ -40,7 +40,7 @@ public abstract class PsiImportStatementBaseImpl extends JavaStubPsiElement<PsiI
|
||||
|
||||
@Override
|
||||
public boolean isOnDemand(){
|
||||
final PsiImportStatementStub stub = getStub();
|
||||
final PsiImportStatementStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.isOnDemand();
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class PsiImportStatementImpl extends PsiImportStatementBaseImpl implement
|
||||
|
||||
@Override
|
||||
public String getQualifiedName() {
|
||||
PsiImportStatementStub stub = getStub();
|
||||
PsiImportStatementStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getImportReferenceText();
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class PsiJavaFileImpl extends PsiJavaFileBaseImpl {
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiJavaModule getModuleDeclaration() {
|
||||
PsiJavaFileStub stub = (PsiJavaFileStub)getStub();
|
||||
PsiJavaFileStub stub = (PsiJavaFileStub)getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getModule();
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class PsiJavaModuleImpl extends JavaStubPsiElement<PsiJavaModuleStub> imp
|
||||
@NotNull
|
||||
@Override
|
||||
public String getModuleName() {
|
||||
PsiJavaModuleStub stub = getStub();
|
||||
PsiJavaModuleStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getName();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.navigation.ItemPresentationProviders;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.ui.Queryable;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.ElementPresentationUtil;
|
||||
@@ -136,7 +137,7 @@ public class PsiMethodImpl extends JavaStubPsiElement<PsiMethodStub> implements
|
||||
@NotNull
|
||||
public String getName() {
|
||||
final String name;
|
||||
final PsiMethodStub stub = getStub();
|
||||
final PsiMethodStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
name = stub.getName();
|
||||
}
|
||||
@@ -241,7 +242,7 @@ public class PsiMethodImpl extends JavaStubPsiElement<PsiMethodStub> implements
|
||||
|
||||
@Override
|
||||
public boolean isDeprecated() {
|
||||
final PsiMethodStub stub = getStub();
|
||||
final PsiMethodStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.isDeprecated() || stub.hasDeprecatedAnnotation() && PsiImplUtil.isDeprecatedByAnnotation(this);
|
||||
}
|
||||
@@ -251,7 +252,7 @@ public class PsiMethodImpl extends JavaStubPsiElement<PsiMethodStub> implements
|
||||
|
||||
@Override
|
||||
public PsiDocComment getDocComment() {
|
||||
final PsiMethodStub stub = getStub();
|
||||
final PsiMethodStub stub = getGreenStub();
|
||||
if (stub != null && !stub.hasDocComment()) return null;
|
||||
|
||||
return (PsiDocComment)getNode().findChildByRoleAsPsiElement(ChildRole.DOC_COMMENT);
|
||||
@@ -259,7 +260,7 @@ public class PsiMethodImpl extends JavaStubPsiElement<PsiMethodStub> implements
|
||||
|
||||
@Override
|
||||
public boolean isConstructor() {
|
||||
final PsiMethodStub stub = getStub();
|
||||
final PsiMethodStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.isConstructor();
|
||||
}
|
||||
@@ -269,7 +270,7 @@ public class PsiMethodImpl extends JavaStubPsiElement<PsiMethodStub> implements
|
||||
|
||||
@Override
|
||||
public boolean isVarArgs() {
|
||||
final PsiMethodStub stub = getStub();
|
||||
final PsiMethodStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.isVarArgs();
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
|
||||
@Override
|
||||
@NotNull
|
||||
public final String getName() {
|
||||
PsiParameterStub stub = getStub();
|
||||
PsiParameterStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getName();
|
||||
}
|
||||
@@ -269,7 +269,7 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
|
||||
|
||||
@Override
|
||||
public boolean isVarArgs() {
|
||||
final PsiParameterStub stub = getStub();
|
||||
final PsiParameterStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.isParameterTypeEllipsis();
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public class PsiParameterListImpl extends JavaStubPsiElement<PsiParameterListStu
|
||||
|
||||
@Override
|
||||
public int getParametersCount() {
|
||||
final PsiParameterListStub stub = getStub();
|
||||
final PsiParameterListStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getChildrenStubs().size();
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class PsiReferenceListImpl extends JavaStubPsiElement<PsiClassReferenceLi
|
||||
@Override
|
||||
@NotNull
|
||||
public PsiClassType[] getReferencedTypes() {
|
||||
PsiClassReferenceListStub stub = getStub();
|
||||
PsiClassReferenceListStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getReferencedTypes();
|
||||
}
|
||||
|
||||
+2
-2
@@ -98,7 +98,7 @@ public class PsiLiteralExpressionImpl
|
||||
}
|
||||
|
||||
public IElementType getLiteralElementType() {
|
||||
PsiLiteralStub stub = getStub();
|
||||
PsiLiteralStub stub = getGreenStub();
|
||||
if (stub != null) return stub.getLiteralType();
|
||||
|
||||
return getNode().getFirstChildNode().getElementType();
|
||||
@@ -111,7 +111,7 @@ public class PsiLiteralExpressionImpl
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
PsiLiteralStub stub = getStub();
|
||||
PsiLiteralStub stub = getGreenStub();
|
||||
if (stub != null) return stub.getLiteralText();
|
||||
|
||||
return super.getText();
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ public class PsiNameValuePairImpl extends JavaStubPsiElement<PsiNameValuePairStu
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiAnnotationMemberValue getDetachedValue() {
|
||||
PsiNameValuePairStub stub = getStub();
|
||||
PsiNameValuePairStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
String text = stub.getValue();
|
||||
PsiAnnotationMemberValue result = SoftReference.dereference(myDetachedValue);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(counting()) with Stream.count()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public long count(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).count();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(mapping()) with Stream.map().collect()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public List<Integer> sizes(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).map(String::length).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(maxBy()) with Stream.max() (may change semantics when result is null)" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public String max(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).max(String.CASE_INSENSITIVE_ORDER).orElse("");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(minBy()) with Stream.min() (may change semantics when result is null)" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public Optional<String> min(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).min(String.CASE_INSENSITIVE_ORDER);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(reducing()) with Stream.reduce() (may change semantics when result is null)" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public Optional<String> concat(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).reduce(String::concat);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(reducing()) with Stream.reduce()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public String concat(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).reduce("", String::concat);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(reducing()) with Stream.map().reduce()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public int sum(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).map(String::length).reduce(0, Integer::sum);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(summingInt()) with Stream.mapToInt().sum()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void remove(List<Integer> ints, List<String> data) {
|
||||
ints.remove((Integer) data.stream().mapToInt(String::length).sum());
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(summingLong()) with Stream.mapToLong().sum()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void remove(List<Integer> ints, List<String> data) {
|
||||
ints.remove(data.stream().mapToLong(String::length).sum());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(counting()) with Stream.count()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public long count(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.<caret>counting());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(mapping()) with Stream.map().collect()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public List<Integer> sizes(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.mapping(Str<caret>ing::length, Collectors.toList()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(maxBy()) with Stream.max() (may change semantics when result is null)" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public String max(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.maxBy(String.CASE_INSENSIT<caret>IVE_ORDER)).orElse("");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(minBy()) with Stream.min() (may change semantics when result is null)" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public Optional<String> min(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.minBy(Str<caret>ing.CASE_INSENSITIVE_ORDER));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(reducing()) with Stream.reduce() (may change semantics when result is null)" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public Optional<String> concat(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).colle<caret>ct(Collectors.reducing(String::concat));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(reducing()) with Stream.reduce()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public String concat(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).colle<caret>ct(Collectors.reducing("", String::concat));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(reducing()) with Stream.map().reduce()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public int sum(List<String> data) {
|
||||
return data.stream().filter(x -> x.startsWith("xyz")).colle<caret>ct(Collectors.reducing(0, String::length, Integer::sum));
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(summingInt()) with Stream.mapToInt().sum()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void remove(List<Integer> ints, List<String> data) {
|
||||
ints.remove(data.stream().collect(Collectors<caret>.summingInt(String::length)));
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream.collect(summingLong()) with Stream.mapToLong().sum()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void remove(List<Integer> ints, List<String> data) {
|
||||
ints.remove(data.stream().collect(Collectors<caret>.summingLong(String::length)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
PsiJavaFile:Provides7.java
|
||||
PsiJavaModule:M
|
||||
PsiKeyword:module('module')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaModuleReference
|
||||
PsiIdentifier:M('M')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiProvidesStatement
|
||||
PsiKeyword:provides('provides')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaCodeReferenceElement:Spi
|
||||
PsiIdentifier:Spi('Spi')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiErrorElement:'with' expected
|
||||
PsiIdentifier:_('_')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
+16
-1
@@ -33,7 +33,22 @@ class ModuleCompletionTest : LightFixtureCompletionTestCase() {
|
||||
addFile("pkg/empty/package-info.java", "package pkg.empty;")
|
||||
addFile("pkg/main/C.java", "package pkg.main;\nclass C { }")
|
||||
addFile("pkg/other/C.groovy", "package pkg.other\nclass C { }")
|
||||
variants("module M { exports pkg.<caret> }", "pkg.main", "pkg.other")
|
||||
variants("module M { exports pkg.<caret> }", "main", "other")
|
||||
complete("module M { exports pkg.o<caret> }", "module M { exports pkg.other;<caret> }")
|
||||
}
|
||||
|
||||
fun testUses() {
|
||||
addFile("pkg/main/MySvc.java", "package pkg.main;\npublic class MySvc { }")
|
||||
addFile("pkg/main/MySvcImpl.java", "package pkg.main;\nclass MySvcImpl extends MySvc { }")
|
||||
complete("module M { uses MyS<caret> }", "module M { uses pkg.main.MySvc;<caret> }")
|
||||
}
|
||||
|
||||
fun testProvides() {
|
||||
addFile("pkg/main/MySvc.java", "package pkg.main;\npublic class MySvc { }")
|
||||
addFile("pkg/main/MySvcImpl.java", "package pkg.main;\nclass MySvcImpl extends MySvc { }")
|
||||
complete("module M { provides MyS<caret> }", "module M { provides pkg.main.MySvc <caret> }")
|
||||
complete("module M { provides pkg.main.MySvc <caret> }", "module M { provides pkg.main.MySvc with <caret> }")
|
||||
complete("module M { provides pkg.main.MySvc with MSI<caret> }", "module M { provides pkg.main.MySvc with pkg.main.MySvcImpl;<caret> }")
|
||||
}
|
||||
|
||||
//<editor-fold desc="Helpers.">
|
||||
|
||||
@@ -69,6 +69,7 @@ public class ModuleParserTest extends JavaParsingTestCase {
|
||||
public void testProvides4() { doParserTest("module M { provides Spi with ; }"); }
|
||||
public void testProvides5() { doParserTest("module M { provides Spi with Impl }"); }
|
||||
public void testProvides6() { doParserTest("module M { provides Spi with Impl; }"); }
|
||||
public void testProvides7() { doParserTest("module M { provides Spi _ }"); }
|
||||
|
||||
private void doParserTest(String text) {
|
||||
doParserTest(text, builder -> JavaParser.INSTANCE.getFileParser().parse(builder));
|
||||
|
||||
+6
-3
@@ -15,12 +15,14 @@
|
||||
*/
|
||||
package com.intellij.refactoring.typeMigration.rules;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase;
|
||||
import com.intellij.refactoring.typeMigration.TypeEvaluator;
|
||||
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.siyeh.ig.controlflow.UnnecessaryReturnInspection;
|
||||
import com.siyeh.ig.fixes.DeleteUnnecessaryStatementFix;
|
||||
import com.siyeh.ig.psiutils.SideEffectChecker;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -43,10 +45,11 @@ public class VoidConversionRule extends TypeConversionRule {
|
||||
@Override
|
||||
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException {
|
||||
final PsiElement parent = expression.getParent();
|
||||
final Project project = expression.getProject();
|
||||
if (parent instanceof PsiReturnStatement) {
|
||||
expression.delete();
|
||||
if (UnnecessaryReturnInspection.isReturnRedundant((PsiReturnStatement)parent, false, null)) {
|
||||
parent.delete();
|
||||
final PsiReturnStatement replaced = (PsiReturnStatement)parent.replace(JavaPsiFacade.getElementFactory(project).createStatementFromText("return;", null));
|
||||
if (UnnecessaryReturnInspection.isReturnRedundant(replaced, false, null)) {
|
||||
DeleteUnnecessaryStatementFix.deleteUnnecessaryStatement(replaced);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* In-memory representation of JVM *.class file produced by a compiler.
|
||||
@@ -84,7 +85,7 @@ public class CompiledClass extends UserDataHolderBase{
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<String> getSourceFilesPaths() {
|
||||
public List<String> getSourceFilesPaths() {
|
||||
return ContainerUtil.map(mySourceFiles, new Function<File, String>() {
|
||||
@Override
|
||||
public String fun(File file) {
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@ import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
|
||||
import com.intellij.compiler.instrumentation.InstrumenterClassWriter;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
import org.jetbrains.jps.incremental.*;
|
||||
@@ -72,7 +73,7 @@ public abstract class BaseInstrumentingBuilder extends ClassProcessingBuilder {
|
||||
LOG.info(e);
|
||||
final String message = e.getMessage();
|
||||
if (message != null) {
|
||||
context.processMessage(new CompilerMessage(getPresentableName(), message, compiledClass.getSourceFilesPaths(), BuildMessage.Kind.ERROR));
|
||||
context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, message, ContainerUtil.getFirstItem(compiledClass.getSourceFilesPaths())));
|
||||
}
|
||||
else {
|
||||
context.processMessage(new CompilerMessage(getPresentableName(), e));
|
||||
|
||||
+2
-2
@@ -93,9 +93,9 @@ public class NotNullInstrumentingBuilder extends BaseInstrumentingBuilder{
|
||||
}
|
||||
}) + ": " + e.getMessage();
|
||||
context.processMessage(new CompilerMessage(getPresentableName(),
|
||||
BuildMessage.Kind.ERROR,
|
||||
msg,
|
||||
compiledClass.getSourceFilesPaths(),
|
||||
BuildMessage.Kind.ERROR));
|
||||
ContainerUtil.getFirstItem(compiledClass.getSourceFilesPaths())));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -16,16 +16,12 @@
|
||||
package org.jetbrains.jps.incremental.messages;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
@@ -37,28 +33,24 @@ public class CompilerMessage extends BuildMessage {
|
||||
private final long myProblemBeginOffset;
|
||||
private final long myProblemEndOffset;
|
||||
private final long myProblemLocationOffset;
|
||||
private final Collection<String> mySourcePaths;
|
||||
private final String mySourcePath;
|
||||
private final long myLine;
|
||||
private final long myColumn;
|
||||
|
||||
public CompilerMessage(@NotNull String compilerName, @NotNull Throwable internalError) {
|
||||
this(compilerName, Kind.ERROR, getTextFromThrowable(internalError));
|
||||
this(compilerName, Kind.ERROR, getTextFromThrowable(internalError), null, -1L, -1L, -1L, -1L, -1L);
|
||||
}
|
||||
|
||||
public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText) {
|
||||
this(compilerName, kind, messageText, (String)null, -1L, -1L, -1L, -1L, -1L);
|
||||
}
|
||||
|
||||
public CompilerMessage(@NotNull String compilerName, String messageText, Collection<String> sourcePaths, Kind kind) {
|
||||
this(compilerName, kind, messageText, sourcePaths, -1L, -1L, -1L, -1L, -1L);
|
||||
this(compilerName, kind, messageText, null, -1L, -1L, -1L, -1L, -1L);
|
||||
}
|
||||
|
||||
public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText, String sourcePath) {
|
||||
this(compilerName, messageText, sourcePath == null ? Collections.<String>emptyList() : Collections.singleton(sourcePath), kind);
|
||||
this(compilerName, kind, messageText, sourcePath, -1L, -1L, -1L, -1L, -1L);
|
||||
}
|
||||
|
||||
public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText,
|
||||
@NotNull Collection<String> sourcePaths,
|
||||
@Nullable String sourcePath,
|
||||
long problemBeginOffset,
|
||||
long problemEndOffset,
|
||||
long problemLocationOffset,
|
||||
@@ -69,34 +61,11 @@ public class CompilerMessage extends BuildMessage {
|
||||
myProblemBeginOffset = problemBeginOffset;
|
||||
myProblemEndOffset = problemEndOffset;
|
||||
myProblemLocationOffset = problemLocationOffset;
|
||||
mySourcePaths = ContainerUtil.map(sourcePaths, new Function<String, String>() {
|
||||
@Override
|
||||
public String fun(String s) {
|
||||
return s.replace(File.separatorChar, '/');
|
||||
}
|
||||
});
|
||||
mySourcePath = sourcePath != null && !sourcePath.isEmpty()? sourcePath.replace(File.separatorChar, '/') : null;
|
||||
myLine = locationLine;
|
||||
myColumn = locationColumn;
|
||||
}
|
||||
|
||||
public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText,
|
||||
@Nullable String sourcePath,
|
||||
long problemBeginOffset,
|
||||
long problemEndOffset,
|
||||
long problemLocationOffset,
|
||||
long locationLine,
|
||||
long locationColumn) {
|
||||
this(compilerName,
|
||||
kind,
|
||||
messageText,
|
||||
sourcePath == null ? Collections.<String>emptyList() : Collections.singleton(sourcePath),
|
||||
problemBeginOffset,
|
||||
problemEndOffset,
|
||||
problemLocationOffset,
|
||||
locationLine,
|
||||
locationColumn);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getCompilerName() {
|
||||
return myCompilerName;
|
||||
@@ -104,7 +73,7 @@ public class CompilerMessage extends BuildMessage {
|
||||
|
||||
@Nullable
|
||||
public String getSourcePath() {
|
||||
return mySourcePaths.size() == 1 ? ContainerUtil.getFirstItem(mySourcePaths) : null;
|
||||
return mySourcePath;
|
||||
}
|
||||
|
||||
public long getLine() {
|
||||
@@ -130,16 +99,7 @@ public class CompilerMessage extends BuildMessage {
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append(getCompilerName()).append(":").append(getKind().name()).append(":").append(super.toString());
|
||||
String result;
|
||||
if (mySourcePaths.isEmpty()) {
|
||||
result = null;
|
||||
}
|
||||
else if (mySourcePaths.size() == 1) {
|
||||
result = ContainerUtil.getFirstItem(mySourcePaths);
|
||||
} else {
|
||||
result = mySourcePaths.toString();
|
||||
}
|
||||
final String path = result;
|
||||
final String path = getSourcePath();
|
||||
if (path != null) {
|
||||
builder.append("; file: ").append(path);
|
||||
final long line = getLine();
|
||||
|
||||
+11
-8
@@ -121,8 +121,7 @@ public class JsonSchemaDefinitionResolver {
|
||||
if (parSchema.getId() != null) {
|
||||
schemaFile = JsonSchemaService.Impl.getEx(myElement.getProject()).getSchemaFileById(parSchema.getId());
|
||||
}
|
||||
return resolveInSomeSchema(definitionAddress.substring(1) + PROPERTIES + propertyName, myElement.getProject(), parSchema.getId(),
|
||||
schemaFile != null ? GlobalSearchScope.fileScope(myElement.getProject(), schemaFile) : null);
|
||||
return resolveInSomeSchema(definitionAddress.substring(1) + PROPERTIES + propertyName, myElement.getProject(), parSchema.getId(), schemaFile);
|
||||
} else {
|
||||
String relative = splitter.getRelativePath();
|
||||
if (StringUtil.isEmptyOrSpaces(relative)) {
|
||||
@@ -139,19 +138,20 @@ public class JsonSchemaDefinitionResolver {
|
||||
if (myRef == null) initializeName();
|
||||
if (myRef == null) return null;
|
||||
|
||||
GlobalSearchScope filter = null;
|
||||
VirtualFile filter = null;
|
||||
if (mySchemaId != null && myRef.startsWith("#/")) {
|
||||
filter = GlobalSearchScope.fileScope(myElement.getContainingFile());
|
||||
filter = myElement.getContainingFile().getVirtualFile();
|
||||
}
|
||||
else {
|
||||
final JsonSchemaServiceEx schemaServiceEx = JsonSchemaService.Impl.getEx(myElement.getProject());
|
||||
final Collection<Pair<VirtualFile, String>> pairs = schemaServiceEx.getSchemaFilesByFile(myElement.getContainingFile().getVirtualFile());
|
||||
if (pairs != null && ! pairs.isEmpty()) {
|
||||
for (Pair<VirtualFile, String> pair : pairs) {
|
||||
final PsiElement element = resolveInSomeSchema(myRef, myElement.getProject(), pair.getSecond(),
|
||||
GlobalSearchScope.fileScope(myElement.getProject(), pair.getFirst()));
|
||||
final PsiElement element = resolveInSomeSchema(myRef, myElement.getProject(), pair.getSecond(), pair.getFirst());
|
||||
if (element != null) return element;
|
||||
}
|
||||
// if not in schema file
|
||||
if (mySchemaId == null) return null;
|
||||
}
|
||||
}
|
||||
return resolveInSomeSchema(myRef, myElement.getProject(), mySchemaId, filter);
|
||||
@@ -161,10 +161,13 @@ public class JsonSchemaDefinitionResolver {
|
||||
private static PsiElement resolveInSomeSchema(@NotNull String referenceName,
|
||||
@NotNull final Project project,
|
||||
@Nullable final String schemaId,
|
||||
final @Nullable GlobalSearchScope filter) {
|
||||
final @Nullable VirtualFile filterFile) {
|
||||
final Ref<Pair<VirtualFile, Integer>> reference = new Ref<>();
|
||||
|
||||
final FileBasedIndex index = FileBasedIndex.getInstance();
|
||||
final GlobalSearchScope fileScope = filterFile == null ? null : GlobalSearchScope.fileScope(project, filterFile);
|
||||
final GlobalSearchScope enlarged = fileScope != null && JsonSchemaResourcesRootsProvider.ourFiles.getValue().contains(filterFile) ? fileScope :
|
||||
JsonSchemaResourcesRootsProvider.enlarge(project, fileScope == null ? GlobalSearchScope.allScope(project) : fileScope);
|
||||
index.processValues(JsonSchemaFileIndex.PROPERTIES_INDEX, referenceName, null, new FileBasedIndex.ValueProcessor<Integer>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile file, Integer value) {
|
||||
@@ -176,7 +179,7 @@ public class JsonSchemaDefinitionResolver {
|
||||
reference.set(Pair.create(file, value));
|
||||
return false;
|
||||
}
|
||||
}, JsonSchemaResourcesRootsProvider.enlarge(project, filter == null ? GlobalSearchScope.allScope(project) : filter));
|
||||
}, enlarged);
|
||||
|
||||
if (!reference.isNull()) {
|
||||
final Pair<VirtualFile, Integer> pair = reference.get();
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class JsonSchemaFileIndex extends FileBasedIndexExtension<String, Integer> {
|
||||
public static final ID<String, Integer> PROPERTIES_INDEX = ID.create("json.schema.properties.index");
|
||||
public static final int VERSION = 4;
|
||||
public static final int VERSION = 5;
|
||||
private IntInlineKeyDescriptor myKeyDescriptor = new IntInlineKeyDescriptor();
|
||||
|
||||
@NotNull
|
||||
|
||||
+7
-3
@@ -159,6 +159,11 @@ public class SeverityRegistrar implements Comparator<HighlightSeverity> {
|
||||
read.add(severity);
|
||||
}
|
||||
}
|
||||
myOrderMap = ensureAllStandardIncluded(read, knownSeverities);
|
||||
severitiesChanged();
|
||||
}
|
||||
|
||||
private OrderMap ensureAllStandardIncluded(List<HighlightSeverity> read, final List<HighlightSeverity> knownSeverities) {
|
||||
OrderMap orderMap = fromList(read);
|
||||
if (orderMap.isEmpty()) {
|
||||
orderMap = fromList(knownSeverities);
|
||||
@@ -182,8 +187,7 @@ public class SeverityRegistrar implements Comparator<HighlightSeverity> {
|
||||
}
|
||||
orderMap = fromList(list);
|
||||
}
|
||||
myOrderMap = orderMap;
|
||||
severitiesChanged();
|
||||
return orderMap;
|
||||
}
|
||||
|
||||
public void writeExternal(Element element) {
|
||||
@@ -345,7 +349,7 @@ public class SeverityRegistrar implements Comparator<HighlightSeverity> {
|
||||
}
|
||||
|
||||
public void setOrder(@NotNull List<HighlightSeverity> orderList) {
|
||||
myOrderMap = fromList(orderList);
|
||||
myOrderMap = ensureAllStandardIncluded(orderList, getDefaultOrder());
|
||||
myReadOrder = null;
|
||||
severitiesChanged();
|
||||
}
|
||||
|
||||
+18
-24
@@ -21,6 +21,7 @@ import com.intellij.codeInspection.ex.InspectionToolRegistrar
|
||||
import com.intellij.configurationStore.SchemeDataHolder
|
||||
import com.intellij.configurationStore.SchemeManagerIprProvider
|
||||
import com.intellij.configurationStore.digest
|
||||
import com.intellij.configurationStore.wrapState
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.PersistentStateComponent
|
||||
@@ -32,7 +33,6 @@ import com.intellij.openapi.project.ProjectManager
|
||||
import com.intellij.openapi.project.ProjectManagerListener
|
||||
import com.intellij.openapi.startup.StartupActivity
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.packageDependencies.DependencyValidationManager
|
||||
import com.intellij.profile.Profile
|
||||
@@ -209,6 +209,23 @@ class ProjectInspectionProfileManager(val project: Project,
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized override fun getState(): Element? {
|
||||
val result = Element("settings")
|
||||
|
||||
schemeManagerIprProvider?.writeState(result)
|
||||
|
||||
val state = this.state
|
||||
state.projectProfile = schemeManager.currentSchemeName
|
||||
XmlSerializer.serializeInto(state, result, skipDefaultsSerializationFilter)
|
||||
if (!result.children.isEmpty()) {
|
||||
result.addContent(Element("version").setAttribute("value", VERSION))
|
||||
}
|
||||
|
||||
severityRegistrar.writeExternal(result)
|
||||
|
||||
return wrapState(result)
|
||||
}
|
||||
|
||||
@Synchronized override fun loadState(state: Element) {
|
||||
val data = state.getChild("settings")
|
||||
|
||||
@@ -250,29 +267,6 @@ class ProjectInspectionProfileManager(val project: Project,
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized override fun getState(): Element? {
|
||||
val result = Element("settings")
|
||||
|
||||
schemeManagerIprProvider?.writeState(result)
|
||||
|
||||
val state = this.state
|
||||
state.projectProfile = schemeManager.currentSchemeName
|
||||
XmlSerializer.serializeInto(state, result, skipDefaultsSerializationFilter)
|
||||
if (!result.children.isEmpty()) {
|
||||
result.addContent(Element("version").setAttribute("value", VERSION))
|
||||
}
|
||||
|
||||
severityRegistrar.writeExternal(result)
|
||||
|
||||
if (JDOMUtil.isEmpty(result)) {
|
||||
result.name = "state"
|
||||
return result
|
||||
}
|
||||
else {
|
||||
return Element("state").addContent(result)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getScopesManager() = scopeManager
|
||||
|
||||
@Synchronized override fun getProfiles(): Collection<Profile> {
|
||||
|
||||
@@ -370,12 +370,16 @@ class SchemeManagerImpl<T : Scheme, MUTABLE_SCHEME : T>(val fileSpec: String,
|
||||
|
||||
override fun updateDigest(scheme: MUTABLE_SCHEME) {
|
||||
try {
|
||||
externalInfo.digest = (processor.writeScheme(scheme) as Element).digest()
|
||||
updateDigest(processor.writeScheme(scheme) as Element)
|
||||
}
|
||||
catch (e: WriteExternalException) {
|
||||
LOG.error("Cannot update digest", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateDigest(data: Element) {
|
||||
externalInfo.digest = data.digest()
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadScheme(fileName: String, input: InputStream, schemes: MutableList<T>, filesToDelete: MutableSet<String>? = null): MUTABLE_SCHEME? {
|
||||
@@ -438,7 +442,7 @@ class SchemeManagerImpl<T : Scheme, MUTABLE_SCHEME : T>(val fileSpec: String,
|
||||
XmlPullParser.START_TAG -> {
|
||||
if (!isUseOldFileNameSanitize || parser.name != "component") {
|
||||
var name: String? = null
|
||||
if (isUseOldFileNameSanitize && parser.name == "profile") {
|
||||
if (isUseOldFileNameSanitize && (parser.name == "profile" || parser.name == "copyright")) {
|
||||
eventType = parser.next()
|
||||
findName@ while (eventType != XmlPullParser.END_DOCUMENT) {
|
||||
when (eventType) {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.diagnostic;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ImplementationConflictException extends RuntimeException {
|
||||
|
||||
@NotNull
|
||||
private final Collection<Class<?>> myConflictingClasses;
|
||||
|
||||
public ImplementationConflictException(String message, Throwable cause, @NotNull Object ...implementationObjects) {
|
||||
super(message, cause);
|
||||
final List<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
for (Object object : implementationObjects) {
|
||||
classes.add(object.getClass());
|
||||
}
|
||||
|
||||
myConflictingClasses = Collections.unmodifiableList(classes);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<Class<?>> getConflictingClasses() {
|
||||
return myConflictingClasses;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.lang;
|
||||
|
||||
import com.intellij.diagnostic.ImplementationConflictException;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
@@ -24,7 +25,6 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -33,12 +33,10 @@ import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* The base class for all programming language support implementations. Specific language implementations should inherit from this class
|
||||
* and its register instance wrapped with {@link com.intellij.openapi.fileTypes.LanguageFileType} instance through
|
||||
* <code>FileTypeManager.getInstance().registerFileType</code>
|
||||
* and its register instance wrapped with {@link LanguageFileType} instance via {@code FileTypeManager.getInstance().registerFileType()}.
|
||||
* There should be exactly one instance of each Language.
|
||||
* It is usually created when creating {@link com.intellij.openapi.fileTypes.LanguageFileType} and can be retrieved later
|
||||
* with {@link #findInstance(Class)}.
|
||||
* For the list of standard languages, see {@link com.intellij.lang.StdLanguages}.
|
||||
* It is usually created when creating {@link LanguageFileType} and can be retrieved later with {@link #findInstance(Class)}.
|
||||
* For the list of standard languages, see {@code com.intellij.lang.StdLanguages}.
|
||||
*/
|
||||
public abstract class Language extends UserDataHolderBase {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.lang.Language");
|
||||
@@ -46,14 +44,15 @@ public abstract class Language extends UserDataHolderBase {
|
||||
private static final Map<Class<? extends Language>, Language> ourRegisteredLanguages = ContainerUtil.newConcurrentMap();
|
||||
private static final ConcurrentMap<String, List<Language>> ourRegisteredMimeTypes = ContainerUtil.newConcurrentMap();
|
||||
private static final Map<String, Language> ourRegisteredIDs = ContainerUtil.newConcurrentMap();
|
||||
|
||||
private final Language myBaseLanguage;
|
||||
private final String myID;
|
||||
private final String[] myMimeTypes;
|
||||
private final List<Language> myDialects = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
|
||||
public static final Language ANY = new Language("") {
|
||||
@Override
|
||||
public String toString() {
|
||||
//noinspection HardCodedStringLiteral
|
||||
return "Language: ANY";
|
||||
}
|
||||
|
||||
@@ -64,28 +63,31 @@ public abstract class Language extends UserDataHolderBase {
|
||||
}
|
||||
};
|
||||
|
||||
protected Language(@NotNull @NonNls String ID) {
|
||||
protected Language(@NotNull String ID) {
|
||||
this(ID, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
}
|
||||
|
||||
protected Language(@NotNull @NonNls final String ID, @NotNull @NonNls final String... mimeTypes) {
|
||||
protected Language(@NotNull String ID, @NotNull String... mimeTypes) {
|
||||
this(null, ID, mimeTypes);
|
||||
}
|
||||
|
||||
protected Language(@Nullable Language baseLanguage, @NotNull @NonNls final String ID, @NotNull @NonNls final String... mimeTypes) {
|
||||
protected Language(@Nullable Language baseLanguage, @NotNull String ID, @NotNull String... mimeTypes) {
|
||||
myBaseLanguage = baseLanguage;
|
||||
myID = ID;
|
||||
myMimeTypes = mimeTypes;
|
||||
|
||||
Class<? extends Language> langClass = getClass();
|
||||
Language prev = ourRegisteredLanguages.put(langClass, this);
|
||||
if (prev != null) {
|
||||
LOG.error("Language of '" + langClass + "' is already registered: " + prev);
|
||||
LOG.error(new ImplementationConflictException("Language of '" + langClass + "' is already registered: " + prev, null, prev, this));
|
||||
return;
|
||||
}
|
||||
|
||||
prev = ourRegisteredIDs.put(ID, this);
|
||||
if (prev != null) {
|
||||
LOG.error("Language with ID '" + ID + "' is already registered: " + prev.getClass());
|
||||
LOG.error(new ImplementationConflictException("Language with ID '" + ID + "' is already registered: " + prev.getClass(), null, prev, this));
|
||||
}
|
||||
|
||||
for (String mimeType : mimeTypes) {
|
||||
if (StringUtil.isEmpty(mimeType)) {
|
||||
continue;
|
||||
@@ -96,6 +98,7 @@ public abstract class Language extends UserDataHolderBase {
|
||||
}
|
||||
languagesByMimeType.add(this);
|
||||
}
|
||||
|
||||
if (baseLanguage != null) {
|
||||
baseLanguage.myDialects.add(this);
|
||||
}
|
||||
@@ -129,10 +132,8 @@ public abstract class Language extends UserDataHolderBase {
|
||||
return result == null ? Collections.<Language>emptyList() : Collections.unmodifiableCollection(result);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
//noinspection HardCodedStringLiteral
|
||||
return "Language: " + myID;
|
||||
}
|
||||
|
||||
@@ -228,4 +229,4 @@ public abstract class Language extends UserDataHolderBase {
|
||||
myBaseLanguage = null;
|
||||
myMimeTypes = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,41 +102,58 @@ public interface Module extends ComponentManager, AreaInstance, Disposable {
|
||||
String getOptionValue(@NotNull String key);
|
||||
|
||||
/**
|
||||
* Returns module scope including sources and tests, excluding libraries and dependencies.
|
||||
*
|
||||
* @return scope including sources and tests, excluding libraries and dependencies.
|
||||
* @return module scope including source and tests, excluding libraries and dependencies.
|
||||
*/
|
||||
@NotNull
|
||||
GlobalSearchScope getModuleScope();
|
||||
|
||||
/**
|
||||
* @param includeTests whether to include test source
|
||||
* @return module scope including source and, optionally, tests, excluding libraries and dependencies.
|
||||
*/
|
||||
@NotNull
|
||||
GlobalSearchScope getModuleScope(boolean includeTests);
|
||||
|
||||
/**
|
||||
* Returns module scope including sources, tests, and libraries, excluding dependencies.
|
||||
*
|
||||
* @return scope including sources, tests, and libraries, excluding dependencies.
|
||||
* @return module scope including source, tests, and libraries, excluding dependencies.
|
||||
*/
|
||||
@NotNull
|
||||
GlobalSearchScope getModuleWithLibrariesScope();
|
||||
|
||||
/**
|
||||
* Returns module scope including sources, tests, and dependencies, excluding libraries.
|
||||
*
|
||||
* @return scope including sources, tests, and dependencies, excluding libraries.
|
||||
* @return module scope including source, tests, and dependencies, excluding libraries.
|
||||
*/
|
||||
@NotNull
|
||||
GlobalSearchScope getModuleWithDependenciesScope();
|
||||
|
||||
/**
|
||||
* @return a scope that includes everything in module content roots, without any dependencies or libraries
|
||||
*/
|
||||
@NotNull
|
||||
GlobalSearchScope getModuleContentScope();
|
||||
|
||||
/**
|
||||
* @return a scope that includes everything under the content roots of this module and its dependencies, with test source
|
||||
*/
|
||||
@NotNull
|
||||
GlobalSearchScope getModuleContentWithDependenciesScope();
|
||||
|
||||
/**
|
||||
* @param includeTests whether test source and test dependencies should be included
|
||||
* @return a scope including module source and dependencies with libraries
|
||||
*/
|
||||
@NotNull
|
||||
GlobalSearchScope getModuleWithDependenciesAndLibrariesScope(boolean includeTests);
|
||||
|
||||
/**
|
||||
* @return a scope including everything under the content roots of this module and all modules that depend on it, directly or indirectly (via exported dependencies), excluding test source and resources
|
||||
*/
|
||||
@NotNull
|
||||
GlobalSearchScope getModuleWithDependentsScope();
|
||||
|
||||
/**
|
||||
* @return same as {@link #getModuleWithDependentsScope()}, but with test source/resources included
|
||||
*/
|
||||
@NotNull
|
||||
GlobalSearchScope getModuleTestsWithDependentsScope();
|
||||
@NotNull
|
||||
|
||||
+7
-8
@@ -383,11 +383,10 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
|
||||
private void registerComponents(@NotNull ComponentConfig config) {
|
||||
ClassLoader loader = config.getClassLoader();
|
||||
try {
|
||||
final Class<?> interfaceClass = Class.forName(config.getInterfaceClass(), true, loader);
|
||||
final Class<?> implementationClass = Comparing.equal(config.getInterfaceClass(), config.getImplementationClass())
|
||||
?
|
||||
interfaceClass
|
||||
: StringUtil.isEmpty(config.getImplementationClass()) ? null : Class.forName(config.getImplementationClass(), true, loader);
|
||||
Class<?> interfaceClass = Class.forName(config.getInterfaceClass(), true, loader);
|
||||
Class<?> implementationClass = Comparing.equal(config.getInterfaceClass(), config.getImplementationClass()) ? interfaceClass :
|
||||
StringUtil.isEmpty(config.getImplementationClass()) ? null :
|
||||
Class.forName(config.getImplementationClass(), true, loader);
|
||||
MutablePicoContainer picoContainer = getPicoContainer();
|
||||
if (config.options != null && Boolean.parseBoolean(config.options.get("overrides"))) {
|
||||
ComponentAdapter oldAdapter = picoContainer.getComponentAdapterOfType(interfaceClass);
|
||||
@@ -398,8 +397,8 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
|
||||
}
|
||||
// implementationClass == null means we want to unregister this component
|
||||
if (implementationClass != null) {
|
||||
picoContainer.registerComponent(new ComponentConfigComponentAdapter(interfaceClass, implementationClass, config.getPluginId(),
|
||||
config.options != null && Boolean.parseBoolean(config.options.get("workspace"))));
|
||||
boolean ws = config.options != null && Boolean.parseBoolean(config.options.get("workspace"));
|
||||
picoContainer.registerComponent(new ComponentConfigComponentAdapter(interfaceClass, implementationClass, config.getPluginId(), ws));
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
@@ -522,4 +521,4 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
|
||||
return "ComponentConfigAdapter[" + getComponentKey() + "]: implementation=" + getComponentImplementation() + ", plugin=" + myPluginId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-7
@@ -115,12 +115,8 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable {
|
||||
|
||||
private void refresh() {
|
||||
int maxIndex = mySeverityRegistrar.getSeverityMaxIndex();
|
||||
if (errorCount != null && maxIndex == errorCount.length) return;
|
||||
int[] newErrors = new int[maxIndex+1];
|
||||
if (errorCount != null) {
|
||||
System.arraycopy(errorCount, 0, newErrors, 0, Math.min(errorCount.length, newErrors.length));
|
||||
}
|
||||
errorCount = newErrors;
|
||||
if (errorCount != null && maxIndex + 1 == errorCount.length) return;
|
||||
errorCount = new int[maxIndex + 1];
|
||||
}
|
||||
|
||||
static void setOrRefreshErrorStripeRenderer(@NotNull EditorMarkupModel editorMarkupModel,
|
||||
@@ -334,7 +330,7 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable {
|
||||
|
||||
Icon icon = AllIcons.General.InspectionsOK;
|
||||
for (int i = status.errorCount.length - 1; i >= 0; i--) {
|
||||
if (status.errorCount[i] != 0) {
|
||||
if (status.errorCount[i] > 0) {
|
||||
icon = SeverityRegistrar.getSeverityRegistrar(project).getRendererIconByIndex(i);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -56,4 +56,10 @@ public abstract class TemplateManager {
|
||||
|
||||
@Nullable
|
||||
public abstract Template getActiveTemplate(@NotNull Editor editor);
|
||||
|
||||
/**
|
||||
* Finished a live template in the given editor, if it's present
|
||||
* @return whether a live template was present
|
||||
*/
|
||||
public abstract boolean finishTemplate(@NotNull Editor editor);
|
||||
}
|
||||
|
||||
+10
@@ -521,6 +521,16 @@ public class TemplateManagerImpl extends TemplateManager implements Disposable {
|
||||
return templateState != null ? templateState.getTemplate() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean finishTemplate(@NotNull Editor editor) {
|
||||
TemplateState state = getTemplateState(editor);
|
||||
if (state != null) {
|
||||
state.gotoEnd();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isApplicable(PsiFile file, int offset, TemplateImpl template) {
|
||||
return isApplicable(template, getApplicableContextTypes(file, offset));
|
||||
}
|
||||
|
||||
+43
-42
@@ -31,16 +31,16 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.SequentialModalProgressTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -74,39 +74,45 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
|
||||
if (!FileModificationService.getInstance().preparePsiElementForWrite(file)) return;
|
||||
|
||||
final List<ProblemDescriptor> descriptions =
|
||||
ProgressManager.getInstance().runProcess(() -> {
|
||||
InspectionManager inspectionManager = InspectionManager.getInstance(project);
|
||||
return InspectionEngine.runInspectionOnFile(file, myToolWrapper, inspectionManager.createNewGlobalContext(false));
|
||||
}, new EmptyProgressIndicator());
|
||||
|
||||
Collections.sort(descriptions, new Comparator<CommonProblemDescriptor>() {
|
||||
@Override
|
||||
public int compare(final CommonProblemDescriptor o1, final CommonProblemDescriptor o2) {
|
||||
final ProblemDescriptorBase d1 = (ProblemDescriptorBase)o1;
|
||||
final ProblemDescriptorBase d2 = (ProblemDescriptorBase)o2;
|
||||
final int offset2 = d2.getTextRange().getStartOffset();
|
||||
final int offset1 = d1.getTextRange().getStartOffset();
|
||||
return offset2 < offset1 ? -1 : offset1 == offset2 ? 0 : 1;
|
||||
}
|
||||
if (!descriptions.isEmpty() && !FileModificationService.getInstance().preparePsiElementForWrite(file)) return;
|
||||
|
||||
final AbstractPerformFixesTask fixesTask = applyFixes(project, "Apply Fixes", descriptions, myQuickfixClass);
|
||||
|
||||
if (!fixesTask.isApplicableFixFound()) {
|
||||
HintManager.getInstance().showErrorHint(editor, "Unfortunately '" + myText + "' is currently not available for batch mode\n User interaction is required for each problem found");
|
||||
}
|
||||
}
|
||||
|
||||
public static AbstractPerformFixesTask applyFixes(@NotNull Project project,
|
||||
@NotNull String presentationText,
|
||||
@NotNull List<ProblemDescriptor> descriptions,
|
||||
@Nullable Class quickfixClass) {
|
||||
Collections.sort(descriptions, (o1, o2) -> {
|
||||
final ProblemDescriptorBase d1 = (ProblemDescriptorBase)o1;
|
||||
final ProblemDescriptorBase d2 = (ProblemDescriptorBase)o2;
|
||||
return -PsiUtilCore.compareElementsByPosition(d1.getPsiElement(), d2.getPsiElement());
|
||||
});
|
||||
|
||||
final String templatePresentationText = "Apply Fixes";
|
||||
|
||||
final SequentialModalProgressTask progressTask =
|
||||
new SequentialModalProgressTask(project, templatePresentationText, true);
|
||||
final boolean isBatch = BatchQuickFix.class.isAssignableFrom(myQuickfixClass);
|
||||
final AbstractPerformFixesTask fixesTask = createTask(project, descriptions.toArray(new ProblemDescriptor[descriptions.size()]), progressTask, isBatch);
|
||||
new SequentialModalProgressTask(project, presentationText, true);
|
||||
final boolean isBatch = quickfixClass != null && BatchQuickFix.class.isAssignableFrom(quickfixClass);
|
||||
final AbstractPerformFixesTask fixesTask = isBatch ?
|
||||
new PerformBatchFixesTask(project, descriptions.toArray(ProblemDescriptor.EMPTY_ARRAY), progressTask, quickfixClass) :
|
||||
new PerformFixesTask(project, descriptions.toArray(ProblemDescriptor.EMPTY_ARRAY), progressTask, quickfixClass);
|
||||
CommandProcessor.getInstance().executeCommand(project, () -> {
|
||||
CommandProcessor.getInstance().markCurrentCommandAsGlobal(project);
|
||||
progressTask.setMinIterationTime(200);
|
||||
progressTask.setTask(fixesTask);
|
||||
ProgressManager.getInstance().run(progressTask);
|
||||
}, templatePresentationText, null);
|
||||
|
||||
if (!fixesTask.isApplicableFixFound()) {
|
||||
HintManager.getInstance().showErrorHint(editor, "Unfortunately '" + myText + "' is currently not available for batch mode\n User interaction is required for each problem found");
|
||||
}
|
||||
}, presentationText, null);
|
||||
return fixesTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,23 +126,16 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AbstractPerformFixesTask createTask(@NotNull Project project,
|
||||
ProblemDescriptor[] descriptions,
|
||||
SequentialModalProgressTask progressTask,
|
||||
boolean isBatch) {
|
||||
return isBatch ?
|
||||
new PerformBatchFixesTask(project, descriptions, progressTask) :
|
||||
new PerformFixesTask(project, descriptions, progressTask);
|
||||
}
|
||||
|
||||
private abstract class AbstractPerformFixesTask extends PerformFixesModalTask {
|
||||
private static abstract class AbstractPerformFixesTask extends PerformFixesModalTask {
|
||||
private boolean myApplicableFixFound = false;
|
||||
protected final Class myQuickfixClass;
|
||||
|
||||
public AbstractPerformFixesTask(@NotNull Project project,
|
||||
@NotNull CommonProblemDescriptor[] descriptors,
|
||||
@NotNull SequentialModalProgressTask task) {
|
||||
@NotNull CommonProblemDescriptor[] descriptors,
|
||||
@NotNull SequentialModalProgressTask task,
|
||||
@Nullable Class quickfixClass) {
|
||||
super(project, descriptors, task);
|
||||
myQuickfixClass = quickfixClass;
|
||||
}
|
||||
|
||||
protected abstract void collectFix(QuickFix fix, ProblemDescriptor descriptor, Project project);
|
||||
@@ -146,7 +145,7 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority
|
||||
final QuickFix[] fixes = descriptor.getFixes();
|
||||
if (fixes != null && fixes.length > 0) {
|
||||
for (final QuickFix fix : fixes) {
|
||||
if (fix != null && fix.getClass().isAssignableFrom(myQuickfixClass)) {
|
||||
if (fix != null && (myQuickfixClass == null || fix.getClass().isAssignableFrom(myQuickfixClass))) {
|
||||
final ProblemDescriptor problemDescriptor = (ProblemDescriptor)descriptor;
|
||||
final PsiElement element = problemDescriptor.getPsiElement();
|
||||
if (element != null && element.isValid()) {
|
||||
@@ -164,14 +163,15 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority
|
||||
}
|
||||
}
|
||||
|
||||
private class PerformBatchFixesTask extends AbstractPerformFixesTask {
|
||||
private static class PerformBatchFixesTask extends AbstractPerformFixesTask {
|
||||
private final List<ProblemDescriptor> myBatchModeDescriptors = new ArrayList<>();
|
||||
private boolean myApplied = false;
|
||||
|
||||
public PerformBatchFixesTask(@NotNull Project project,
|
||||
@NotNull CommonProblemDescriptor[] descriptors,
|
||||
@NotNull SequentialModalProgressTask task) {
|
||||
super(project, descriptors, task);
|
||||
@NotNull SequentialModalProgressTask task,
|
||||
@NotNull Class quickfixClass) {
|
||||
super(project, descriptors, task, quickfixClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -204,11 +204,12 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority
|
||||
}
|
||||
}
|
||||
|
||||
private class PerformFixesTask extends AbstractPerformFixesTask {
|
||||
private static class PerformFixesTask extends AbstractPerformFixesTask {
|
||||
public PerformFixesTask(@NotNull Project project,
|
||||
@NotNull CommonProblemDescriptor[] descriptors,
|
||||
@NotNull SequentialModalProgressTask task) {
|
||||
super(project, descriptors, task);
|
||||
@NotNull SequentialModalProgressTask task,
|
||||
@Nullable Class quickFixClass) {
|
||||
super(project, descriptors, task, quickFixClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+59
-54
@@ -20,10 +20,10 @@ import com.intellij.analysis.AnalysisScope;
|
||||
import com.intellij.analysis.AnalysisUIOptions;
|
||||
import com.intellij.analysis.PerformAnalysisInBackgroundOption;
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoProcessor;
|
||||
import com.intellij.codeInsight.daemon.impl.LocalInspectionsPass;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.actions.CleanupInspectionIntention;
|
||||
import com.intellij.codeInspection.lang.GlobalInspectionContextExtension;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
@@ -47,7 +47,6 @@ import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.application.TransactionGuard;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.components.PathMacroManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
@@ -77,8 +76,9 @@ import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.GuiUtils;
|
||||
import com.intellij.ui.content.*;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.*;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jdom.Element;
|
||||
@@ -92,6 +92,7 @@ import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.*;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class GlobalInspectionContextImpl extends GlobalInspectionContextBase implements GlobalInspectionContext {
|
||||
@@ -889,8 +890,6 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
final List<LocalInspectionToolWrapper> lTools = new ArrayList<>();
|
||||
|
||||
final LinkedHashMap<PsiFile, List<HighlightInfo>> results = new LinkedHashMap<>();
|
||||
|
||||
final SearchScope searchScope = scope.toSearchScope();
|
||||
final TextRange range;
|
||||
if (searchScope instanceof LocalSearchScope) {
|
||||
@@ -909,47 +908,66 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
assert tools != null;
|
||||
return tools.getTool().getTool() instanceof CleanupLocalInspectionTool;
|
||||
});
|
||||
List<ProblemDescriptor> descriptors = new ArrayList<>();
|
||||
Set<PsiFile> files = new HashSet<>();
|
||||
boolean includeDoNotShow = includeDoNotShow(profile);
|
||||
scope.accept(new PsiElementVisitor() {
|
||||
private int myCount;
|
||||
@Override
|
||||
public void visitFile(PsiFile file) {
|
||||
if (progressIndicator != null) {
|
||||
progressIndicator.setFraction((double)++myCount / fileCount);
|
||||
}
|
||||
if (isBinary(file)) return;
|
||||
for (final Tools tools : inspectionTools) {
|
||||
final InspectionToolWrapper tool = tools.getEnabledTool(file, includeDoNotShow);
|
||||
if (tool instanceof LocalInspectionToolWrapper) {
|
||||
lTools.add((LocalInspectionToolWrapper)tool);
|
||||
tool.initialize(GlobalInspectionContextImpl.this);
|
||||
final RefManagerImpl refManager = (RefManagerImpl)getRefManager();
|
||||
refManager.inspectionReadActionStarted();
|
||||
try {
|
||||
scope.accept(new PsiElementVisitor() {
|
||||
private int myCount;
|
||||
@Override
|
||||
public void visitFile(PsiFile file) {
|
||||
if (progressIndicator != null) {
|
||||
progressIndicator.setFraction((double)++myCount / fileCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (!lTools.isEmpty()) {
|
||||
final LocalInspectionsPass pass = new LocalInspectionsPass(file, PsiDocumentManager.getInstance(getProject()).getDocument(file), range != null ? range.getStartOffset() : 0,
|
||||
range != null ? range.getEndOffset() : file.getTextLength(), LocalInspectionsPass.EMPTY_PRIORITY_RANGE, true,
|
||||
HighlightInfoProcessor.getEmpty());
|
||||
Runnable runnable = () -> pass.doInspectInBatch(GlobalInspectionContextImpl.this, InspectionManager.getInstance(getProject()), lTools);
|
||||
ApplicationManager.getApplication().runReadAction(runnable);
|
||||
final List<HighlightInfo> infos = pass.getInfos();
|
||||
if (searchScope instanceof LocalSearchScope) {
|
||||
for (Iterator<HighlightInfo> iterator = infos.iterator(); iterator.hasNext(); ) {
|
||||
final HighlightInfo info = iterator.next();
|
||||
final TextRange infoRange = new TextRange(info.getStartOffset(), info.getEndOffset());
|
||||
if (!((LocalSearchScope)searchScope).containsRange(file, infoRange)) {
|
||||
iterator.remove();
|
||||
}
|
||||
if (isBinary(file)) return;
|
||||
for (final Tools tools : inspectionTools) {
|
||||
final InspectionToolWrapper tool = tools.getEnabledTool(file, includeDoNotShow);
|
||||
if (tool instanceof LocalInspectionToolWrapper) {
|
||||
lTools.add((LocalInspectionToolWrapper)tool);
|
||||
tool.initialize(GlobalInspectionContextImpl.this);
|
||||
}
|
||||
}
|
||||
if (!infos.isEmpty()) {
|
||||
results.put(file, infos);
|
||||
|
||||
if (!lTools.isEmpty()) {
|
||||
final LocalInspectionsPass pass = new LocalInspectionsPass(file, PsiDocumentManager.getInstance(getProject()).getDocument(file), range != null ? range.getStartOffset() : 0,
|
||||
range != null ? range.getEndOffset() : file.getTextLength(), LocalInspectionsPass.EMPTY_PRIORITY_RANGE, true,
|
||||
HighlightInfoProcessor.getEmpty());
|
||||
Runnable runnable = () -> pass.doInspectInBatch(GlobalInspectionContextImpl.this, InspectionManager.getInstance(getProject()), lTools);
|
||||
ApplicationManager.getApplication().runReadAction(runnable);
|
||||
|
||||
List<ProblemDescriptor> localDescriptors = new ArrayList<>();
|
||||
for (LocalInspectionToolWrapper tool : lTools) {
|
||||
for (CommonProblemDescriptor descriptor : getPresentation(tool).getProblemDescriptors()) {
|
||||
if (descriptor instanceof ProblemDescriptor) {
|
||||
localDescriptors.add((ProblemDescriptor)descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (searchScope instanceof LocalSearchScope) {
|
||||
for (Iterator<ProblemDescriptor> iterator = localDescriptors.iterator(); iterator.hasNext(); ) {
|
||||
final ProblemDescriptor descriptor = iterator.next();
|
||||
final TextRange infoRange = descriptor instanceof ProblemDescriptorBase ? ((ProblemDescriptorBase)descriptor).getTextRange() : null;
|
||||
if (infoRange != null && !((LocalSearchScope)searchScope).containsRange(file, infoRange)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!localDescriptors.isEmpty()) {
|
||||
descriptors.addAll(localDescriptors);
|
||||
files.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
finally {
|
||||
refManager.inspectionReadActionFinished();
|
||||
}
|
||||
|
||||
if (results.isEmpty()) {
|
||||
if (files.isEmpty()) {
|
||||
GuiUtils.invokeLaterIfNeeded(() -> {
|
||||
if (commandName != null) {
|
||||
NOTIFICATION_GROUP.createNotification(InspectionsBundle.message("inspection.no.problems.message", scope.getFileCount(), scope.getDisplayName()), MessageType.INFO).notify(getProject());
|
||||
@@ -961,21 +979,8 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
return;
|
||||
}
|
||||
Runnable runnable = () -> {
|
||||
if (!FileModificationService.getInstance().preparePsiElementsForWrite(results.keySet())) return;
|
||||
|
||||
final String title = "Code Cleanup";
|
||||
final SequentialModalProgressTask progressTask = new SequentialModalProgressTask(getProject(), title, true);
|
||||
progressTask.setMinIterationTime(200);
|
||||
progressTask.setTask(new SequentialCleanupTask(getProject(), results, progressTask));
|
||||
CommandProcessor.getInstance().executeCommand(getProject(), () -> {
|
||||
if (commandName != null) {
|
||||
CommandProcessor.getInstance().markCurrentCommandAsGlobal(getProject());
|
||||
}
|
||||
ProgressManager.getInstance().run(progressTask);
|
||||
if (postRunnable != null) {
|
||||
ApplicationManager.getApplication().invokeLater(postRunnable);
|
||||
}
|
||||
}, title, null);
|
||||
if (!FileModificationService.getInstance().preparePsiElementsForWrite(files)) return;
|
||||
CleanupInspectionIntention.applyFixes(getProject(), "Code Cleanup", descriptors, null);
|
||||
};
|
||||
TransactionGuard.submitTransaction(getProject(), runnable);
|
||||
}
|
||||
|
||||
+18
-13
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.ex;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.QuickFix;
|
||||
import com.intellij.codeInspection.reference.RefDirectory;
|
||||
@@ -279,21 +280,25 @@ public abstract class InspectionRVContentProvider {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (RefElementNode parentNode : parentNodes) {
|
||||
final List<ProblemDescriptionNode> nodes = new ArrayList<>();
|
||||
TreeUtil.traverse(parentNode, new TreeUtil.Traverse() {
|
||||
@Override
|
||||
public boolean accept(final Object node) {
|
||||
if (node instanceof ProblemDescriptionNode) {
|
||||
nodes.add((ProblemDescriptionNode)node);
|
||||
|
||||
//allow unused declaration to have structure at file level even when there are unused parameters
|
||||
if (!HighlightInfoType.UNUSED_SYMBOL_SHORT_NAME.equals(toolWrapper.getShortName())) {
|
||||
for (RefElementNode parentNode : parentNodes) {
|
||||
final List<ProblemDescriptionNode> nodes = new ArrayList<>();
|
||||
TreeUtil.traverse(parentNode, new TreeUtil.Traverse() {
|
||||
@Override
|
||||
public boolean accept(final Object node) {
|
||||
if (node instanceof ProblemDescriptionNode) {
|
||||
nodes.add((ProblemDescriptionNode)node);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (nodes.isEmpty()) continue;
|
||||
parentNode.removeAllChildren();
|
||||
for (ProblemDescriptionNode node : nodes) {
|
||||
parentNode.add(node);
|
||||
}
|
||||
});
|
||||
if (nodes.isEmpty()) continue; //FilteringInspectionTool == DeadCode
|
||||
parentNode.removeAllChildren();
|
||||
for (ProblemDescriptionNode node : nodes) {
|
||||
parentNode.add(node);
|
||||
}
|
||||
}
|
||||
for (RefElementNode node : parentNodes) {
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final InspectionToolWrapper toolWrapper, @NotNull final InspectionTree tree) {
|
||||
final RefEntity[] refEntities = tree.getSelectedElements();
|
||||
InspectionToolPresentation presentation = tree.getContext().getPresentation(toolWrapper);
|
||||
return refEntities.length == 0 ? null : presentation.getQuickFixes(refEntities, tree.getSelectedDescriptors());
|
||||
return refEntities.length == 0 ? null : presentation.getQuickFixes(refEntities, tree);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* 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.codeInspection.ex;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.SequentialModalProgressTask;
|
||||
import com.intellij.util.SequentialTask;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class SequentialCleanupTask implements SequentialTask {
|
||||
private static final Logger LOG = Logger.getInstance(SequentialCleanupTask.class);
|
||||
|
||||
private final Project myProject;
|
||||
private final List<Pair<PsiFile, HighlightInfo>> myResults = new ArrayList<>();
|
||||
private final SequentialModalProgressTask myProgressTask;
|
||||
private int myCount = 0;
|
||||
|
||||
public SequentialCleanupTask(Project project, LinkedHashMap<PsiFile, List<HighlightInfo>> results, SequentialModalProgressTask task) {
|
||||
myProject = project;
|
||||
for (Map.Entry<PsiFile, List<HighlightInfo>> entry : results.entrySet()) {
|
||||
PsiFile file = entry.getKey();
|
||||
List<HighlightInfo> infos = entry.getValue();
|
||||
// sort from bottom to top
|
||||
Collections.sort(infos, (info1, info2) -> info2.getStartOffset() - info1.getStartOffset());
|
||||
for (HighlightInfo info : infos) {
|
||||
myResults.add(Pair.create(file, info));
|
||||
}
|
||||
}
|
||||
myProgressTask = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return myCount > myResults.size() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean iteration() {
|
||||
final Pair<PsiFile, HighlightInfo> pair = myResults.get(myCount++);
|
||||
final ProgressIndicator indicator = myProgressTask.getIndicator();
|
||||
if (indicator != null) {
|
||||
indicator.setFraction((double) myCount/myResults.size());
|
||||
indicator.setText("Processing " + pair.first.getName());
|
||||
}
|
||||
for (final Pair<HighlightInfo.IntentionActionDescriptor, TextRange> actionRange : pair.second.quickFixActionRanges) {
|
||||
final AccessToken token = WriteAction.start();
|
||||
try {
|
||||
actionRange.getFirst().getAction().invoke(myProject, null, pair.first);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
finally {
|
||||
token.finish();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {}
|
||||
}
|
||||
+2
-2
@@ -618,8 +618,8 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) {
|
||||
return extractActiveFixes(refElements, getProblemElements(), allowedDescriptors);
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, InspectionTree tree) {
|
||||
return extractActiveFixes(refElements, getProblemElements(), tree != null ? tree.getSelectedDescriptors() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor
|
||||
@NotNull
|
||||
Set<RefModule> getModuleProblems();
|
||||
@Nullable
|
||||
QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, @Nullable CommonProblemDescriptor[] descriptors);
|
||||
QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, @Nullable InspectionTree tree);
|
||||
@NotNull
|
||||
Map<RefEntity, CommonProblemDescriptor[]> getProblemElements();
|
||||
@NotNull
|
||||
|
||||
+1
-4
@@ -52,7 +52,7 @@ public class FileTemplateSettings extends FileTemplatesLoader implements Persist
|
||||
@Nullable
|
||||
@Override
|
||||
public Element getState() {
|
||||
Element element = null;
|
||||
Element element = new Element("fileTemplateSettings");
|
||||
for (FTManager manager : getAllManagers()) {
|
||||
Element templatesGroup = null;
|
||||
for (FileTemplateBase template : manager.getAllTemplates(true)) {
|
||||
@@ -75,9 +75,6 @@ public class FileTemplateSettings extends FileTemplatesLoader implements Persist
|
||||
|
||||
if (templatesGroup == null) {
|
||||
templatesGroup = new Element(getXmlElementGroupName(manager));
|
||||
if (element == null) {
|
||||
element = new Element("fileTemplateSettings");
|
||||
}
|
||||
element.addContent(templatesGroup);
|
||||
}
|
||||
templatesGroup.addContent(templateElement);
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,13 +22,13 @@ import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowFactoryEx;
|
||||
import com.intellij.openapi.wm.ToolWindowFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class ProjectViewToolWindowFactory implements ToolWindowFactoryEx, DumbAware {
|
||||
public class ProjectViewToolWindowFactory implements ToolWindowFactory, DumbAware {
|
||||
@Override
|
||||
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
|
||||
((ProjectViewImpl) ProjectView.getInstance(project)).setupImpl(toolWindow);
|
||||
|
||||
+1
-3
@@ -667,9 +667,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable
|
||||
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
final InspectionProfileImpl inspectionProfile = myProfiles.getProfilesComboBox().getSelectedProfile();
|
||||
SingleInspectionProfilePanel panel = getProfilePanel(inspectionProfile);
|
||||
return panel == null ? null : panel.getPreferredFocusedComponent();
|
||||
return myProfilePanelHolder;
|
||||
}
|
||||
|
||||
private void showProfile(InspectionProfileImpl profile) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,8 +23,24 @@ import org.jetbrains.annotations.NotNull;
|
||||
* Performs lazy initialization of a toolwindow registered in plugin.xml.
|
||||
*
|
||||
* @author yole
|
||||
* @author Konstantin Bulenkov
|
||||
* @see ToolWindowEP
|
||||
*/
|
||||
public interface ToolWindowFactory {
|
||||
void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow);
|
||||
|
||||
/**
|
||||
* Perform additional initialisation routine here
|
||||
* @param window Tool Window
|
||||
*/
|
||||
default void init(ToolWindow window) {}
|
||||
|
||||
/**
|
||||
* Tool Window saves its state on project close and restore on when project opens
|
||||
* In some cases, it is useful to postpone Tool Window activation until user explicitly activates it.
|
||||
* Example: Tool Window initialisation takes huge amount of time and makes project loading slower.
|
||||
* @return {@code true} if Tool Window should not be activated on start even if was opened previously.
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
default boolean isDoNotActivateOnStart() {return false;}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,7 @@ package com.intellij.openapi.wm;
|
||||
|
||||
/**
|
||||
* @author Dennis.Ushakov
|
||||
* @deprecated use {@link ToolWindowFactory}
|
||||
*/
|
||||
public interface ToolWindowFactoryEx extends ToolWindowFactory {
|
||||
void init(ToolWindow window);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.diagnostic;
|
||||
|
||||
import com.intellij.diagnostic.errordialog.PluginConflictDialog;
|
||||
import com.intellij.ide.plugins.cl.PluginClassLoader;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public enum PluginConflictReporter {
|
||||
INSTANCE;
|
||||
|
||||
public void reportConflictByClasses(@NotNull Collection<Class<?>> conflictingClasses) {
|
||||
final Set<PluginId> foundPlugins = new HashSet<>();
|
||||
boolean hasConflictWithPlatform = false;
|
||||
|
||||
if (conflictingClasses.size() < 2) {
|
||||
throw new IllegalArgumentException("The conflict should has been caused by at least two classes");
|
||||
}
|
||||
|
||||
for (Class<?> aClass : conflictingClasses) {
|
||||
final ClassLoader classLoader = aClass.getClassLoader();
|
||||
if (classLoader instanceof PluginClassLoader) {
|
||||
foundPlugins.add(((PluginClassLoader)classLoader).getPluginId());
|
||||
}
|
||||
else {
|
||||
hasConflictWithPlatform = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundPlugins.isEmpty()) {
|
||||
Logger.getInstance(PluginConflictReporter.class).warn("The conflict has not come from PluginClassLoader");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean finalHasConflictWithPlatform = hasConflictWithPlatform;
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
final JFrame frame = WindowManager.getInstance().findVisibleFrame();
|
||||
if (frame != null) {
|
||||
new PluginConflictDialog(frame, new ArrayList<>(foundPlugins), finalHasConflictWithPlatform).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.diagnostic.errordialog.PluginConflictDialog">
|
||||
<grid id="27dc6" binding="myContentPane" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="500" height="400"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<preferredSize width="400" height="-1"/>
|
||||
</properties>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="94dfc" class="com.intellij.ui.components.JBLabel" binding="myTopMessageLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<grid id="99a5b" binding="myConflictingPluginsListPanel" custom-create="true" layout-manager="FlowLayout" hgap="5" vgap="5" flow-align="0">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
<component id="d6b86" class="com.intellij.ui.components.JBLabel" binding="myBottomMessageLabel">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<vspacer id="a4d4f">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.diagnostic.errordialog;
|
||||
|
||||
import com.intellij.diagnostic.DiagnosticBundle;
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.ide.plugins.PluginManager;
|
||||
import com.intellij.ide.plugins.PluginManagerConfigurable;
|
||||
import com.intellij.ide.plugins.PluginManagerCore;
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.JBRadioButton;
|
||||
import com.intellij.util.ui.JBEmptyBorder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PluginConflictDialog extends DialogWrapper {
|
||||
public static final int WIDTH = 510;
|
||||
|
||||
@NotNull
|
||||
private final List<PluginId> myConflictingPlugins;
|
||||
|
||||
private final boolean myIsConflictWithPlatform;
|
||||
@Nullable
|
||||
private final List<JBRadioButton> myRadioButtons;
|
||||
|
||||
private JPanel myContentPane;
|
||||
|
||||
private JBLabel myTopMessageLabel;
|
||||
|
||||
private JPanel myConflictingPluginsListPanel;
|
||||
|
||||
private JBLabel myBottomMessageLabel;
|
||||
|
||||
public PluginConflictDialog(@NotNull Component parent,
|
||||
@NotNull List<PluginId> conflictingPlugins,
|
||||
boolean isConflictWithPlatform) {
|
||||
super(parent, false);
|
||||
|
||||
myConflictingPlugins = conflictingPlugins;
|
||||
myIsConflictWithPlatform = isConflictWithPlatform;
|
||||
|
||||
if (myIsConflictWithPlatform) {
|
||||
myRadioButtons = null;
|
||||
}
|
||||
else {
|
||||
myRadioButtons = new ArrayList<>();
|
||||
}
|
||||
|
||||
$$$setupUI$$$();
|
||||
setTitle(DiagnosticBundle.message("error.dialog.conflict.plugin.title"));
|
||||
init();
|
||||
|
||||
myTopMessageLabel.setText(getTopMessageText(conflictingPlugins, isConflictWithPlatform));
|
||||
myBottomMessageLabel.setText(DiagnosticBundle.message("error.dialog.conflict.plugin.footer"));
|
||||
|
||||
myTopMessageLabel.setPreferredSize(new Dimension(WIDTH, (int)myTopMessageLabel.getPreferredSize().getHeight()));
|
||||
myContentPane.setPreferredSize(new Dimension(WIDTH, (int)myContentPane.getMinimumSize().getHeight()));
|
||||
}
|
||||
|
||||
private static String getTopMessageText(@NotNull List<PluginId> conflictingPlugins, boolean isConflictWithPlatform) {
|
||||
final int pluginsNumber = conflictingPlugins.size();
|
||||
if (isConflictWithPlatform) {
|
||||
return DiagnosticBundle.message("error.dialog.conflict.plugin.header.platform", pluginsNumber);
|
||||
}
|
||||
else {
|
||||
final List<String> names = conflictingPlugins.stream()
|
||||
.map(PluginConflictDialog::getPluginNameOrId)
|
||||
.map(s -> "<b>" + s + "</b>")
|
||||
.collect(Collectors.toList());
|
||||
return DiagnosticBundle.message("error.dialog.conflict.plugin.header.each.other",
|
||||
StringUtil.join(names.subList(0, pluginsNumber - 1), ", "),
|
||||
names.get(pluginsNumber - 1));
|
||||
}
|
||||
}
|
||||
|
||||
private void $$$setupUI$$$() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return myContentPane;
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
final ButtonGroup buttonGroup = new ButtonGroup();
|
||||
|
||||
myConflictingPluginsListPanel = new JPanel(new GridLayout(0, 1));
|
||||
final List<JPanel> pluginDescriptions = myConflictingPlugins.stream()
|
||||
.map(plugin -> getChooserPanelForPlugin(buttonGroup, plugin))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!myIsConflictWithPlatform) {
|
||||
pluginDescriptions.add(0, getChooserPanelForPlugin(buttonGroup, null));
|
||||
}
|
||||
|
||||
for (JPanel panel : pluginDescriptions) {
|
||||
myConflictingPluginsListPanel.add(panel);
|
||||
}
|
||||
|
||||
setUpDefaultSelection();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JPanel getChooserPanelForPlugin(@NotNull ButtonGroup buttonGroup, @Nullable PluginId plugin) {
|
||||
final JPanel panel = new JPanel(new BorderLayout());
|
||||
if (!myIsConflictWithPlatform) {
|
||||
assert myRadioButtons != null;
|
||||
|
||||
final JBRadioButton radioButton = new JBRadioButton();
|
||||
myRadioButtons.add(radioButton);
|
||||
buttonGroup.add(radioButton);
|
||||
|
||||
panel.add(radioButton, BorderLayout.WEST);
|
||||
panel.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
radioButton.setSelected(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final JPanel descriptionPanel;
|
||||
if (plugin != null) {
|
||||
descriptionPanel = getPluginDescriptionPanel(plugin, !myIsConflictWithPlatform);
|
||||
}
|
||||
else {
|
||||
descriptionPanel = getDisableAllPanel();
|
||||
}
|
||||
descriptionPanel.setBorder(new JBEmptyBorder(10, myIsConflictWithPlatform ? 10 : 0, 10, 20));
|
||||
|
||||
panel.add(descriptionPanel, BorderLayout.CENTER);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private void setUpDefaultSelection() {
|
||||
if (myIsConflictWithPlatform) {
|
||||
return;
|
||||
}
|
||||
assert myRadioButtons != null && myRadioButtons.size() == myConflictingPlugins.size() + 1;
|
||||
|
||||
for (int i = 0; i < myConflictingPlugins.size(); i++) {
|
||||
final IdeaPluginDescriptor pluginDescriptor = PluginManager.getPlugin(myConflictingPlugins.get(i));
|
||||
if (pluginDescriptor != null
|
||||
&& (pluginDescriptor.isBundled() || StringUtil.equalsIgnoreCase(pluginDescriptor.getVendor(), "JetBrains"))) {
|
||||
myRadioButtons.get(i).setSelected(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
myRadioButtons.get(myRadioButtons.size() - 1).setSelected(true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JPanel getPluginDescriptionPanel(@NotNull PluginId plugin, boolean addUseWord) {
|
||||
final JPanel panel = new JPanel(new BorderLayout());
|
||||
|
||||
final IdeaPluginDescriptor pluginDescriptor = PluginManager.getPlugin(plugin);
|
||||
if (pluginDescriptor == null) {
|
||||
panel.add(new JBLabel(plugin.getIdString()), BorderLayout.CENTER);
|
||||
return panel;
|
||||
}
|
||||
|
||||
final StringBuilder sb = new StringBuilder("<html>");
|
||||
if (addUseWord) {
|
||||
sb.append("Use ");
|
||||
}
|
||||
sb.append(pluginDescriptor.getName());
|
||||
if (pluginDescriptor.getVendor() != null) {
|
||||
sb.append(" by ").append(pluginDescriptor.getVendor());
|
||||
}
|
||||
sb.append("</html>");
|
||||
panel.add(new JBLabel(sb.toString()));
|
||||
return panel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getPluginNameOrId(@NotNull PluginId pluginId) {
|
||||
final IdeaPluginDescriptor pluginDescriptor = PluginManager.getPlugin(pluginId);
|
||||
if (pluginDescriptor == null) {
|
||||
return pluginId.getIdString();
|
||||
}
|
||||
else {
|
||||
return pluginDescriptor.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JPanel getDisableAllPanel() {
|
||||
final JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(new JBLabel(DiagnosticBundle.message("error.dialog.conflict.plugin.disable.all")));
|
||||
return panel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Action getOKAction() {
|
||||
return new DisableAction();
|
||||
}
|
||||
|
||||
private class DisableAction extends DialogWrapperAction {
|
||||
protected DisableAction() {
|
||||
super(DiagnosticBundle.message("error.dialog.disable.plugin.action.disable"));
|
||||
putValue(DEFAULT_ACTION, Boolean.TRUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction(ActionEvent e) {
|
||||
for (int i = 0; i < myConflictingPlugins.size(); ++i) {
|
||||
if (myRadioButtons == null || !myRadioButtons.get(i).isSelected()) {
|
||||
PluginManagerCore.disablePlugin(myConflictingPlugins.get(i).getIdString());
|
||||
}
|
||||
}
|
||||
close(OK_EXIT_CODE);
|
||||
PluginManagerConfigurable.shutdownOrRestartApp("");
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user