mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-02 00:57:59 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
Generated
+2
@@ -31,6 +31,8 @@
|
||||
<module name="groovy_rt" target="1.5" />
|
||||
<module name="java-runtime" target="1.3" />
|
||||
<module name="javac2" target="1.5" />
|
||||
<module name="jps-launcher" target="1.6" />
|
||||
<module name="junit_rt" target="1.3" />
|
||||
</bytecodeTargetLevel>
|
||||
</component>
|
||||
<component name="EclipseCompilerSettings">
|
||||
|
||||
Generated
+11
@@ -0,0 +1,11 @@
|
||||
<component name="libraryTable">
|
||||
<library name="ForkJoin">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/jsr166e.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/src/jsr166e_src.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -100,8 +100,7 @@ import org.jetbrains.jps.cmdline.ClasspathBootstrap;
|
||||
import org.jetbrains.jps.incremental.Utils;
|
||||
import org.jetbrains.jps.model.serialization.JpsGlobalLoader;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.ToolProvider;
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -890,7 +889,8 @@ public class
|
||||
launcherCp.add(ClasspathBootstrap.getResourcePath(launcherClass));
|
||||
launcherCp.add(compilerPath);
|
||||
ClasspathBootstrap.appendJavaCompilerClasspath(launcherCp);
|
||||
|
||||
// this will disable standard extensions to ensure javac is loaded from the right tools.jar
|
||||
cmdLine.addParameter("-Djava.ext.dirs=");
|
||||
cmdLine.addParameter("-classpath");
|
||||
cmdLine.addParameter(classpathToString(launcherCp));
|
||||
|
||||
|
||||
@@ -170,6 +170,8 @@ public class FrameVariablesTree extends DebuggerTree {
|
||||
final DebuggerTreeNodeImpl variableNode = myNodeManager.createNode(descriptor, evaluationContext);
|
||||
myChildren.add(variableNode);
|
||||
}
|
||||
myChildren.add(myNodeManager.createMessageNode(MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE));
|
||||
// trying to collect values from variable slots
|
||||
final List<DecompiledLocalVariable> decompiled = collectVariablesFromBytecode(frame, argValues.size());
|
||||
if (!decompiled.isEmpty()) {
|
||||
try {
|
||||
@@ -185,7 +187,6 @@ public class FrameVariablesTree extends DebuggerTree {
|
||||
LOG.info(ex);
|
||||
}
|
||||
}
|
||||
myChildren.add(myNodeManager.createMessageNode(MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE));
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
|
||||
+88
-37
@@ -70,47 +70,12 @@ public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{
|
||||
final PsiCodeBlock body = method.getBody();
|
||||
if (body != null) {
|
||||
final StringBuilder nameBuilder = new StringBuilder();
|
||||
nameBuilder.append(myDefaultName);
|
||||
try {
|
||||
final int startSlot = params.getParametersCount() + (method.hasModifierProperty(PsiModifier.STATIC)? 0 : 1);
|
||||
body.accept(new JavaRecursiveElementVisitor() {
|
||||
private int myCurrentSlotIndex = startSlot;
|
||||
private final Stack<Integer> myIndexStack = new Stack<Integer>();
|
||||
@Override
|
||||
public void visitCodeBlock(PsiCodeBlock block) {
|
||||
myIndexStack.push(myCurrentSlotIndex);
|
||||
try {
|
||||
super.visitCodeBlock(block);
|
||||
}
|
||||
finally {
|
||||
myCurrentSlotIndex = myIndexStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(PsiLocalVariable variable) {
|
||||
if (myCurrentSlotIndex == myIndex) {
|
||||
if (nameBuilder.length() == myDefaultName.length()) {
|
||||
nameBuilder.append(": ");
|
||||
}
|
||||
else {
|
||||
nameBuilder.append("|");
|
||||
}
|
||||
nameBuilder.append(variable.getName());
|
||||
}
|
||||
final PsiType varType = variable.getType();
|
||||
myCurrentSlotIndex += (varType == PsiType.DOUBLE || varType == PsiType.LONG)? 2 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
// skip local and anonymous classes
|
||||
}
|
||||
|
||||
});
|
||||
body.accept(new LocalVariableNameFinder(startSlot, nameBuilder));
|
||||
}
|
||||
finally {
|
||||
myName = nameBuilder.toString();
|
||||
myName = nameBuilder.length() > 0? myDefaultName + ": " + nameBuilder.toString() : myDefaultName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,4 +106,90 @@ public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{
|
||||
throw new EvaluateException(DebuggerBundle.message("error.invalid.local.variable.name", getName()), e);
|
||||
}
|
||||
}
|
||||
|
||||
private class LocalVariableNameFinder extends JavaRecursiveElementVisitor {
|
||||
private final int myStartSlot;
|
||||
private final StringBuilder myNameBuilder;
|
||||
private int myCurrentSlotIndex;
|
||||
private final Stack<Integer> myIndexStack;
|
||||
|
||||
public LocalVariableNameFinder(int startSlot, StringBuilder nameBuilder) {
|
||||
myStartSlot = startSlot;
|
||||
myNameBuilder = nameBuilder;
|
||||
myCurrentSlotIndex = myStartSlot;
|
||||
myIndexStack = new Stack<Integer>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(PsiLocalVariable variable) {
|
||||
if (myCurrentSlotIndex == myIndex) {
|
||||
if (myNameBuilder.length() != 0) {
|
||||
myNameBuilder.append("|");
|
||||
}
|
||||
myNameBuilder.append(variable.getName());
|
||||
}
|
||||
final PsiType varType = variable.getType();
|
||||
myCurrentSlotIndex += (varType == PsiType.DOUBLE || varType == PsiType.LONG)? 2 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCodeBlock(PsiCodeBlock block) {
|
||||
myIndexStack.push(myCurrentSlotIndex);
|
||||
try {
|
||||
super.visitCodeBlock(block);
|
||||
}
|
||||
finally {
|
||||
myCurrentSlotIndex = myIndexStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitForStatement(PsiForStatement statement) {
|
||||
myIndexStack.push(myCurrentSlotIndex);
|
||||
try {
|
||||
super.visitForStatement(statement);
|
||||
}
|
||||
finally {
|
||||
myCurrentSlotIndex = myIndexStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitForeachStatement(PsiForeachStatement statement) {
|
||||
myIndexStack.push(myCurrentSlotIndex);
|
||||
try {
|
||||
super.visitForeachStatement(statement);
|
||||
}
|
||||
finally {
|
||||
myCurrentSlotIndex = myIndexStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCatchSection(PsiCatchSection section) {
|
||||
myIndexStack.push(myCurrentSlotIndex);
|
||||
try {
|
||||
super.visitCatchSection(section);
|
||||
}
|
||||
finally {
|
||||
myCurrentSlotIndex = myIndexStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitResourceList(PsiResourceList resourceList) {
|
||||
myIndexStack.push(myCurrentSlotIndex);
|
||||
try {
|
||||
super.visitResourceList(resourceList);
|
||||
}
|
||||
finally {
|
||||
myCurrentSlotIndex = myIndexStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
// skip local and anonymous classes
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,21 +19,24 @@ import com.intellij.execution.Location;
|
||||
import com.intellij.execution.actions.ConfigurationContext;
|
||||
import com.intellij.execution.junit2.info.MethodLocation;
|
||||
import com.intellij.ide.util.PsiClassListCellRenderer;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.TextEditor;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.util.PsiClassUtil;
|
||||
import com.intellij.ui.ColoredListCellRenderer;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Processor;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
@@ -68,7 +71,7 @@ public class InheritorChooser {
|
||||
ClassInheritorsSearch.search(containingClass).forEach(new Processor<PsiClass>() {
|
||||
@Override
|
||||
public boolean process(PsiClass aClass) {
|
||||
if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
if (PsiClassUtil.isRunnableClass(aClass, true, true)) {
|
||||
classes.add(aClass);
|
||||
}
|
||||
return true;
|
||||
@@ -84,6 +87,19 @@ public class InheritorChooser {
|
||||
return true;
|
||||
}
|
||||
if (classes.isEmpty()) return false;
|
||||
final FileEditor fileEditor = PlatformDataKeys.FILE_EDITOR.getData(context.getDataContext());
|
||||
if (fileEditor instanceof TextEditor) {
|
||||
final Document document = ((TextEditor)fileEditor).getEditor().getDocument();
|
||||
final PsiFile containingFile = PsiDocumentManager.getInstance(context.getProject()).getPsiFile(document);
|
||||
if (containingFile instanceof PsiClassOwner) {
|
||||
final List<PsiClass> psiClasses = new ArrayList<PsiClass>(Arrays.asList(((PsiClassOwner)containingFile).getClasses()));
|
||||
psiClasses.retainAll(classes);
|
||||
if (psiClasses.size() == 1) {
|
||||
runForClass(psiClasses.get(0), psiMethod, context, performRunnable);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiClassListCellRenderer renderer = new PsiClassListCellRenderer() {
|
||||
@Override
|
||||
protected boolean customizeNonPsiElementLeftRenderer(ColoredListCellRenderer renderer,
|
||||
|
||||
@@ -15,19 +15,14 @@
|
||||
*/
|
||||
package com.intellij.ide.projectWizard;
|
||||
|
||||
import com.intellij.framework.FrameworkGroup;
|
||||
import com.intellij.ide.util.frameworkSupport.FrameworkRole;
|
||||
import com.intellij.ide.util.projectWizard.ModuleBuilder;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
@@ -69,11 +64,6 @@ public abstract class ProjectCategory {
|
||||
return new FrameworkRole[] {createModuleBuilder().getDefaultAcceptableRole()};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FrameworkGroup getAssociatedFrameworkGroup() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String[] getAssociatedFrameworkIds() {
|
||||
return ArrayUtil.EMPTY_STRING_ARRAY;
|
||||
@@ -83,15 +73,4 @@ public abstract class ProjectCategory {
|
||||
public String toString() {
|
||||
return getDisplayName();
|
||||
}
|
||||
|
||||
private static Map<String, ProjectCategory> map = ContainerUtil.newMapFromValues(Arrays.asList(EXTENSION_POINT_NAME.getExtensions()).iterator(), new Convertor<ProjectCategory, String>() {
|
||||
@Override
|
||||
public String convert(ProjectCategory o) {
|
||||
return o.getId();
|
||||
}
|
||||
});
|
||||
|
||||
public static ProjectCategory findById(String id) {
|
||||
return map.get(id);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -276,7 +276,9 @@ public class GenericsHighlightUtil {
|
||||
return checkExtendsWildcardCaptureFailure((PsiWildcardType)type, bound);
|
||||
}
|
||||
else if (((PsiWildcardType)type).isSuper()) {
|
||||
return checkNotAssignable(bound, ((PsiWildcardType)type).getSuperBound(), false);
|
||||
final PsiType superBound = ((PsiWildcardType)type).getSuperBound();
|
||||
if (PsiUtil.resolveClassInType(superBound) instanceof PsiTypeParameter) return TypesDistinctProver.provablyDistinct(type, bound);
|
||||
return checkNotAssignable(bound, superBound, false);
|
||||
}
|
||||
}
|
||||
else if (type instanceof PsiArrayType) {
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.dependencyViolation;
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.packageDependencies.DependenciesBuilder;
|
||||
import com.intellij.packageDependencies.DependencyRule;
|
||||
import com.intellij.packageDependencies.DependencyValidationManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DependencyInspectionBase extends AbstractBaseJavaLocalInspectionTool {
|
||||
private static final String GROUP_DISPLAY_NAME = "";
|
||||
private static final String DISPLAY_NAME = InspectionsBundle.message("illegal.package.dependencies");
|
||||
@NonNls private static final String SHORT_NAME = "Dependency";
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getGroupDisplayName() {
|
||||
return GROUP_DISPLAY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return DISPLAY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getShortName() {
|
||||
return SHORT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ProblemDescriptor[] checkFile(@NotNull final PsiFile file, @NotNull final InspectionManager manager, final boolean isOnTheFly) {
|
||||
if (file.getViewProvider().getPsi(JavaLanguage.INSTANCE) == null) return null;
|
||||
final DependencyValidationManager validationManager = DependencyValidationManager.getInstance(file.getProject());
|
||||
if (!validationManager.hasRules()) return null;
|
||||
if (validationManager.getApplicableRules(file).length == 0) return null;
|
||||
final List<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
|
||||
DependenciesBuilder.analyzeFileDependencies(file, new DependenciesBuilder.DependencyProcessor() {
|
||||
@Override
|
||||
public void process(PsiElement place, PsiElement dependency) {
|
||||
PsiFile dependencyFile = dependency.getContainingFile();
|
||||
if (dependencyFile != null && dependencyFile.isPhysical() && dependencyFile.getVirtualFile() != null) {
|
||||
final DependencyRule[] rule = validationManager.getViolatorDependencyRules(file, dependencyFile);
|
||||
for (DependencyRule dependencyRule : rule) {
|
||||
problems.add(manager.createProblemDescriptor(place, InspectionsBundle
|
||||
.message("inspection.dependency.violator.problem.descriptor", dependencyRule.getDisplayText()), isOnTheFly,
|
||||
createEditDependencyFixes(dependencyRule),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return problems.isEmpty() ? null : problems.toArray(new ProblemDescriptor[problems.size()]);
|
||||
}
|
||||
|
||||
protected LocalQuickFix[] createEditDependencyFixes(DependencyRule dependencyRule) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public HighlightDisplayLevel getDefaultLevel() {
|
||||
return HighlightDisplayLevel.ERROR;
|
||||
}
|
||||
}
|
||||
+262
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.javaDoc;
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.javadoc.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class JavaDocReferenceInspectionBase extends AbstractBaseJavaLocalInspectionTool {
|
||||
@NonNls private static final String SHORT_NAME = "JavadocReference";
|
||||
|
||||
private static ProblemDescriptor createDescriptor(@NotNull PsiElement element, String template, InspectionManager manager,
|
||||
boolean onTheFly) {
|
||||
return manager.createProblemDescriptor(element, template, onTheFly, null, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
|
||||
public void visitRefInDocTag(final PsiDocTag tag,
|
||||
final JavadocManager manager,
|
||||
final PsiElement context,
|
||||
final List<ProblemDescriptor> problems,
|
||||
final InspectionManager inspectionManager,
|
||||
final boolean onTheFly) {
|
||||
final String tagName = tag.getName();
|
||||
final PsiDocTagValue value = tag.getValueElement();
|
||||
if (value == null) return;
|
||||
final JavadocTagInfo info = manager.getTagInfo(tagName);
|
||||
if (info != null && !info.isValidInContext(context)) return;
|
||||
final String message = info == null || !info.isInline() ? null : info.checkTagValue(value);
|
||||
if (message != null){
|
||||
problems.add(createDescriptor(value, message, inspectionManager, onTheFly));
|
||||
}
|
||||
|
||||
final PsiReference reference = value.getReference();
|
||||
if (reference == null) return;
|
||||
final PsiElement element = reference.resolve();
|
||||
if (element != null) return;
|
||||
final int textOffset = value.getTextOffset();
|
||||
if (textOffset == value.getTextRange().getEndOffset()) return;
|
||||
final PsiDocTagValue valueElement = tag.getValueElement();
|
||||
if (valueElement == null) return;
|
||||
|
||||
final CharSequence paramName = value.getContainingFile().getViewProvider().getContents().subSequence(textOffset, value.getTextRange().getEndOffset());
|
||||
final String params = "<code>" + paramName + "</code>";
|
||||
final List<LocalQuickFix> fixes = new ArrayList<LocalQuickFix>();
|
||||
if (onTheFly && "param".equals(tagName)) {
|
||||
final PsiDocCommentOwner commentOwner = PsiTreeUtil.getParentOfType(tag, PsiDocCommentOwner.class);
|
||||
if (commentOwner instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)commentOwner;
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
final PsiDocTag[] tags = tag.getContainingComment().getTags();
|
||||
final Set<String> unboundParams = new HashSet<String>();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!JavaDocLocalInspectionBase.isFound(tags, parameter)) {
|
||||
unboundParams.add(parameter.getName());
|
||||
}
|
||||
}
|
||||
if (!unboundParams.isEmpty()) {
|
||||
fixes.add(createRenameReferenceQuickFix(unboundParams));
|
||||
}
|
||||
}
|
||||
}
|
||||
fixes.add(new RemoveTagFix(tagName, paramName));
|
||||
|
||||
problems.add(inspectionManager.createProblemDescriptor(valueElement, reference.getRangeInElement(), cannotResolveSymbolMessage(params),
|
||||
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly,
|
||||
fixes.toArray(new LocalQuickFix[fixes.size()])));
|
||||
}
|
||||
|
||||
protected LocalQuickFix createRenameReferenceQuickFix(Set<String> unboundParams) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String cannotResolveSymbolMessage(String params) {
|
||||
return InspectionsBundle.message("inspection.javadoc.problem.cannot.resolve", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
if (!PsiPackage.PACKAGE_INFO_FILE.equals(file.getName()) || !(file instanceof PsiJavaFile)) {
|
||||
return null;
|
||||
}
|
||||
final PsiDocComment docComment = PsiTreeUtil.getChildOfType(file, PsiDocComment.class);
|
||||
final PsiJavaFile javaFile = (PsiJavaFile)file;
|
||||
final String packageName = javaFile.getPackageName();
|
||||
final PsiPackage aPackage = JavaPsiFacade.getInstance(file.getProject()).findPackage(packageName);
|
||||
return checkComment(docComment, aPackage, manager, isOnTheFly);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ProblemDescriptor[] checkMethod(@NotNull PsiMethod psiMethod, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
return checkMember(psiMethod, manager, isOnTheFly);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ProblemDescriptor[] checkField(@NotNull PsiField field, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
return checkMember(field, manager, isOnTheFly);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
return checkMember(aClass, manager, isOnTheFly);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ProblemDescriptor[] checkMember(final PsiDocCommentOwner docCommentOwner, final InspectionManager manager, final boolean isOnTheFly) {
|
||||
return checkComment(docCommentOwner.getDocComment(), docCommentOwner, manager, isOnTheFly);
|
||||
}
|
||||
|
||||
private ProblemDescriptor[] checkComment(PsiDocComment docComment, PsiElement context, InspectionManager manager, boolean isOnTheFly) {
|
||||
if (docComment == null) return null;
|
||||
|
||||
final List<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
|
||||
final Set<PsiJavaCodeReferenceElement> references = new HashSet<PsiJavaCodeReferenceElement>();
|
||||
docComment.accept(getVisitor(references, context, problems, manager, isOnTheFly));
|
||||
for (PsiJavaCodeReferenceElement reference : references) {
|
||||
final PsiElement referenceNameElement = reference.getReferenceNameElement();
|
||||
problems.add(manager.createProblemDescriptor(referenceNameElement != null ? referenceNameElement : reference,
|
||||
cannotResolveSymbolMessage("<code>" + reference.getText() + "</code>"),
|
||||
!isOnTheFly ? null : createAddQualifierFix(reference),
|
||||
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, isOnTheFly));
|
||||
}
|
||||
|
||||
return problems.isEmpty() ? null : problems.toArray(new ProblemDescriptor[problems.size()]);
|
||||
}
|
||||
|
||||
protected LocalQuickFix createAddQualifierFix(PsiJavaCodeReferenceElement reference) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private PsiElementVisitor getVisitor(final Set<PsiJavaCodeReferenceElement> references,
|
||||
final PsiElement context,
|
||||
final List<ProblemDescriptor> problems,
|
||||
final InspectionManager manager,
|
||||
final boolean onTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
visitElement(expression);
|
||||
}
|
||||
|
||||
@Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
|
||||
super.visitReferenceElement(reference);
|
||||
JavaResolveResult result = reference.advancedResolve(false);
|
||||
if (result.getElement() == null && !result.isPackagePrefixPackageReference()) {
|
||||
references.add(reference);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitDocTag(PsiDocTag tag) {
|
||||
super.visitDocTag(tag);
|
||||
final JavadocManager javadocManager = JavadocManager.SERVICE.getInstance(tag.getProject());
|
||||
final JavadocTagInfo info = javadocManager.getTagInfo(tag.getName());
|
||||
if (info == null || !info.isInline()) {
|
||||
visitRefInDocTag(tag, javadocManager, context, problems, manager, onTheFly);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitInlineDocTag(PsiInlineDocTag tag) {
|
||||
super.visitInlineDocTag(tag);
|
||||
final JavadocManager javadocManager = JavadocManager.SERVICE.getInstance(tag.getProject());
|
||||
visitRefInDocTag(tag, javadocManager, context, problems, manager, onTheFly);
|
||||
}
|
||||
|
||||
@Override public void visitElement(PsiElement element) {
|
||||
PsiElement[] children = element.getChildren();
|
||||
for (PsiElement child : children) {
|
||||
//do not visit method javadoc twice
|
||||
if (!(child instanceof PsiDocCommentOwner)) {
|
||||
child.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionsBundle.message("inspection.javadoc.ref.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getGroupDisplayName() {
|
||||
return InspectionsBundle.message("group.names.javadoc.issues");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getShortName() {
|
||||
return SHORT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public HighlightDisplayLevel getDefaultLevel() {
|
||||
return HighlightDisplayLevel.ERROR;
|
||||
}
|
||||
|
||||
private static class RemoveTagFix implements LocalQuickFix {
|
||||
private final String myTagName;
|
||||
private final CharSequence myParamName;
|
||||
|
||||
public RemoveTagFix(String tagName, CharSequence paramName) {
|
||||
myTagName = tagName;
|
||||
myParamName = paramName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return "Remove @" + myTagName + " " + myParamName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiDocTag myTag = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiDocTag.class);
|
||||
if (myTag == null) return;
|
||||
if (!FileModificationService.getInstance().preparePsiElementForWrite(myTag)) return;
|
||||
myTag.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -85,7 +85,8 @@ class TypeArgumentCompletionProvider extends CompletionProvider<CompletionParame
|
||||
PsiElement context,
|
||||
final PsiClass actualClass,
|
||||
final int index,
|
||||
PsiClassType.ClassResolveResult expectedType, TailType globalTail) {
|
||||
PsiClassType.ClassResolveResult expectedType,
|
||||
TailType globalTail) {
|
||||
final PsiClass expectedClass = expectedType.getElement();
|
||||
|
||||
if (!InheritanceUtil.isInheritorOrSelf(actualClass, expectedClass, true)) return;
|
||||
|
||||
@@ -26,6 +26,8 @@ import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.*;
|
||||
@@ -261,12 +263,12 @@ public class GenerateMembersUtil {
|
||||
|
||||
try {
|
||||
final PsiMethod resultMethod = createMethod(factory, sourceMethod, target);
|
||||
copyDocComment(sourceMethod, resultMethod, factory);
|
||||
copyModifiers(sourceMethod.getModifierList(), resultMethod.getModifierList());
|
||||
final PsiSubstitutor collisionResolvedSubstitutor =
|
||||
substituteTypeParameters(factory, target, sourceMethod.getTypeParameterList(), resultMethod.getTypeParameterList(), substitutor, sourceMethod);
|
||||
substituteReturnType(PsiManager.getInstance(project), resultMethod, sourceMethod.getReturnType(), collisionResolvedSubstitutor);
|
||||
substituteParameters(factory, codeStyleManager, sourceMethod.getParameterList(), resultMethod.getParameterList(), collisionResolvedSubstitutor, target);
|
||||
copyDocComment(sourceMethod, resultMethod, factory);
|
||||
final List<PsiClassType> thrownTypes = ExceptionUtil.collectSubstituted(collisionResolvedSubstitutor, sourceMethod.getThrowsList().getReferencedTypes());
|
||||
if (target instanceof PsiClass) {
|
||||
final PsiClass[] supers = ((PsiClass)target).getSupers();
|
||||
@@ -435,6 +437,18 @@ public class GenerateMembersUtil {
|
||||
target.addAfter(factory.createDocCommentFromText(docComment.getText()), null);
|
||||
}
|
||||
}
|
||||
final PsiParameter[] sourceParameters = source.getParameterList().getParameters();
|
||||
final PsiParameterList targetParameterList = target.getParameterList();
|
||||
RefactoringUtil.fixJavadocsForParams(target, new HashSet<PsiParameter>(Arrays.asList(targetParameterList.getParameters())), new Condition<Pair<PsiParameter, String>>() {
|
||||
@Override
|
||||
public boolean value(Pair<PsiParameter, String> pair) {
|
||||
final int parameterIndex = targetParameterList.getParameterIndex(pair.first);
|
||||
if (parameterIndex >= 0 && parameterIndex < sourceParameters.length) {
|
||||
return Comparing.strEqual(pair.second, sourceParameters[parameterIndex].getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+3
-1
@@ -18,9 +18,9 @@ package com.intellij.codeInsight.generation.surroundWith;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.StdLanguages;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -65,6 +65,8 @@ public class XmlSurroundWithRangeAdjuster implements SurroundWithRangeAdjuster {
|
||||
lang2 = getLanguage(element2);
|
||||
|
||||
if(lang1 != lang2) return null;
|
||||
|
||||
TextRange.assertProperRange(startOffset, endOffset, "Wrong offsets for " + selectedRange.substring(file.getText()));
|
||||
return new TextRange(startOffset, endOffset);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-73
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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,60 +15,33 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.dependencyViolation;
|
||||
|
||||
import com.intellij.analysis.AnalysisScope;
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
|
||||
import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.lang.StdLanguages;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.packageDependencies.DependenciesBuilder;
|
||||
import com.intellij.packageDependencies.DependencyRule;
|
||||
import com.intellij.packageDependencies.DependencyValidationManager;
|
||||
import com.intellij.packageDependencies.ForwardDependenciesBuilder;
|
||||
import com.intellij.packageDependencies.ui.DependencyConfigurable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
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.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: Feb 6, 2005
|
||||
*/
|
||||
public class DependencyInspection extends BaseLocalInspectionTool {
|
||||
|
||||
public static final String GROUP_DISPLAY_NAME = "";
|
||||
public static final String DISPLAY_NAME = InspectionsBundle.message("illegal.package.dependencies");
|
||||
@NonNls public static final String SHORT_NAME = "Dependency";
|
||||
public class DependencyInspection extends DependencyInspectionBase {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getGroupDisplayName() {
|
||||
return DependencyInspection.GROUP_DISPLAY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return DependencyInspection.DISPLAY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getShortName() {
|
||||
return DependencyInspection.SHORT_NAME;
|
||||
protected LocalQuickFix[] createEditDependencyFixes(DependencyRule dependencyRule) {
|
||||
return new LocalQuickFix[]{
|
||||
new EditDependencyRulesAction(dependencyRule)};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,42 +61,6 @@ public class DependencyInspection extends BaseLocalInspectionTool {
|
||||
return depPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ProblemDescriptor[] checkFile(@NotNull final PsiFile file, @NotNull final InspectionManager manager, final boolean isOnTheFly) {
|
||||
if (file == null) return null;
|
||||
if (file.getViewProvider().getPsi(StdLanguages.JAVA) == null) return null;
|
||||
final DependencyValidationManager validationManager = DependencyValidationManager.getInstance(file.getProject());
|
||||
if (!validationManager.hasRules()) return null;
|
||||
if (validationManager.getApplicableRules(file).length == 0) return null;
|
||||
final ArrayList<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
|
||||
ForwardDependenciesBuilder builder = new ForwardDependenciesBuilder(file.getProject(), new AnalysisScope(file));
|
||||
DependenciesBuilder.analyzeFileDependencies(file, new DependenciesBuilder.DependencyProcessor() {
|
||||
@Override
|
||||
public void process(PsiElement place, PsiElement dependency) {
|
||||
PsiFile dependencyFile = dependency.getContainingFile();
|
||||
if (dependencyFile != null && dependencyFile.isPhysical() && dependencyFile.getVirtualFile() != null) {
|
||||
final DependencyRule[] rule = validationManager.getViolatorDependencyRules(file, dependencyFile);
|
||||
for (DependencyRule dependencyRule : rule) {
|
||||
StringBuffer message = new StringBuffer();
|
||||
message
|
||||
.append(InspectionsBundle.message("inspection.dependency.violator.problem.descriptor", dependencyRule.getDisplayText()));
|
||||
problems.add(manager.createProblemDescriptor(place, message.toString(), isOnTheFly,
|
||||
new LocalQuickFix[]{new EditDependencyRulesAction(dependencyRule)},
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return problems.isEmpty() ? null : problems.toArray(new ProblemDescriptor[problems.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public HighlightDisplayLevel getDefaultLevel() {
|
||||
return HighlightDisplayLevel.ERROR;
|
||||
}
|
||||
|
||||
private static class EditDependencyRulesAction implements LocalQuickFix {
|
||||
private final DependencyRule myRule;
|
||||
public EditDependencyRulesAction(DependencyRule rule) {
|
||||
@@ -146,7 +83,5 @@ public class DependencyInspection extends BaseLocalInspectionTool {
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
ShowSettingsUtil.getInstance().editConfigurable(project, new DependencyConfigurable(project));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-6
@@ -139,6 +139,7 @@ public class InferNullityAnnotationsAction extends BaseAnalysisAction {
|
||||
}
|
||||
}
|
||||
});
|
||||
restartAnalysis(project, scope);
|
||||
}
|
||||
}
|
||||
else if (Messages.showOkCancelDialog(project, "Infer Nullity Annotations requires that the nullity annotations" +
|
||||
@@ -163,12 +164,7 @@ public class InferNullityAnnotationsAction extends BaseAnalysisAction {
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
analyze(project, scope);
|
||||
}
|
||||
});
|
||||
restartAnalysis(project, scope);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -228,6 +224,15 @@ public class InferNullityAnnotationsAction extends BaseAnalysisAction {
|
||||
SwingUtilities.invokeLater(applyRunnable);
|
||||
}
|
||||
|
||||
private void restartAnalysis(final Project project, final AnalysisScope scope) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
analyze(project, scope);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected JComponent getAdditionalActionSettings(Project project, BaseAnalysisActionDialog dialog) {
|
||||
|
||||
+49
-253
@@ -15,15 +15,14 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.javaDoc;
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFix;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemDescriptorBase;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.util.FQNameCellRenderer;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
@@ -36,203 +35,75 @@ import com.intellij.openapi.ui.popup.PopupChooserBuilder;
|
||||
import com.intellij.openapi.util.AsyncResult;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.javadoc.*;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaCodeReferenceElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.proximity.PsiProximityComparator;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class JavaDocReferenceInspection extends BaseLocalInspectionTool {
|
||||
@NonNls public static final String SHORT_NAME = "JavadocReference";
|
||||
|
||||
private static ProblemDescriptor createDescriptor(@NotNull PsiElement element, String template, InspectionManager manager,
|
||||
boolean onTheFly) {
|
||||
return manager.createProblemDescriptor(element, template, onTheFly, null, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public class JavaDocReferenceInspection extends JavaDocReferenceInspectionBase {
|
||||
@Override
|
||||
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
if (!PsiPackage.PACKAGE_INFO_FILE.equals(file.getName()) || !(file instanceof PsiJavaFile)) {
|
||||
return null;
|
||||
}
|
||||
final PsiDocComment docComment = PsiTreeUtil.getChildOfType(file, PsiDocComment.class);
|
||||
final PsiJavaFile javaFile = (PsiJavaFile)file;
|
||||
final String packageName = javaFile.getPackageName();
|
||||
final PsiPackage aPackage = JavaPsiFacade.getInstance(file.getProject()).findPackage(packageName);
|
||||
return checkComment(docComment, aPackage, manager, isOnTheFly);
|
||||
protected LocalQuickFix createAddQualifierFix(PsiJavaCodeReferenceElement reference) {
|
||||
List<PsiClass> classesToImport = new ImportClassFix(reference).getClassesToImport();
|
||||
return classesToImport.isEmpty() ? null : new JavaDocReferenceInspection.AddQualifierFix(classesToImport);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ProblemDescriptor[] checkMethod(@NotNull PsiMethod psiMethod, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
return checkMember(psiMethod, manager, isOnTheFly);
|
||||
protected RenameReferenceQuickFix createRenameReferenceQuickFix(Set<String> unboundParams) {
|
||||
return new RenameReferenceQuickFix(unboundParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ProblemDescriptor[] checkField(@NotNull PsiField field, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
return checkMember(field, manager, isOnTheFly);
|
||||
}
|
||||
private static class RenameReferenceQuickFix implements LocalQuickFix {
|
||||
private final Set<String> myUnboundParams;
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
return checkMember(aClass, manager, isOnTheFly);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ProblemDescriptor[] checkMember(final PsiDocCommentOwner docCommentOwner, final InspectionManager manager, final boolean isOnTheFly) {
|
||||
return checkComment(docCommentOwner.getDocComment(), docCommentOwner, manager, isOnTheFly);
|
||||
}
|
||||
|
||||
private ProblemDescriptor[] checkComment(PsiDocComment docComment, PsiElement context, InspectionManager manager, boolean isOnTheFly) {
|
||||
if (docComment == null) return null;
|
||||
|
||||
final ArrayList<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
|
||||
final Set<PsiJavaCodeReferenceElement> references = new HashSet<PsiJavaCodeReferenceElement>();
|
||||
docComment.accept(getVisitor(references, context, problems, manager, isOnTheFly));
|
||||
for (PsiJavaCodeReferenceElement reference : references) {
|
||||
final List<PsiClass> classesToImport = new ImportClassFix(reference).getClassesToImport();
|
||||
final PsiElement referenceNameElement = reference.getReferenceNameElement();
|
||||
problems.add(manager.createProblemDescriptor(referenceNameElement != null ? referenceNameElement : reference,
|
||||
cannotResolveSymbolMessage("<code>" + reference.getText() + "</code>"),
|
||||
!isOnTheFly || classesToImport.isEmpty() ? null : new AddQualifierFix(classesToImport),
|
||||
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, isOnTheFly));
|
||||
public RenameReferenceQuickFix(Set<String> unboundParams) {
|
||||
myUnboundParams = unboundParams;
|
||||
}
|
||||
|
||||
return problems.isEmpty() ? null : problems.toArray(new ProblemDescriptor[problems.size()]);
|
||||
}
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return "Change to ...";
|
||||
}
|
||||
|
||||
private PsiElementVisitor getVisitor(final Set<PsiJavaCodeReferenceElement> references,
|
||||
final PsiElement context,
|
||||
final ArrayList<ProblemDescriptor> problems,
|
||||
final InspectionManager manager,
|
||||
final boolean onTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
visitElement(expression);
|
||||
}
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
|
||||
super.visitReferenceElement(reference);
|
||||
JavaResolveResult result = reference.advancedResolve(false);
|
||||
if (result.getElement() == null && !result.isPackagePrefixPackageReference()) {
|
||||
references.add(reference);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
|
||||
final AsyncResult<DataContext> asyncResult = DataManager.getInstance().getDataContextFromFocus();
|
||||
asyncResult.doWhenDone(new AsyncResult.Handler<DataContext>() {
|
||||
@Override
|
||||
public void run(DataContext dataContext) {
|
||||
final Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
|
||||
assert editor != null;
|
||||
final TextRange textRange = ((ProblemDescriptorBase)descriptor).getTextRange();
|
||||
editor.getSelectionModel().setSelection(textRange.getStartOffset(), textRange.getEndOffset());
|
||||
|
||||
@Override public void visitDocTag(PsiDocTag tag) {
|
||||
super.visitDocTag(tag);
|
||||
final JavadocManager javadocManager = JavadocManager.SERVICE.getInstance(tag.getProject());
|
||||
final JavadocTagInfo info = javadocManager.getTagInfo(tag.getName());
|
||||
if (info == null || !info.isInline()) {
|
||||
visitRefInDocTag(tag, javadocManager, context, problems, manager, onTheFly);
|
||||
}
|
||||
}
|
||||
final String word = editor.getSelectionModel().getSelectedText();
|
||||
|
||||
@Override public void visitInlineDocTag(PsiInlineDocTag tag) {
|
||||
super.visitInlineDocTag(tag);
|
||||
final JavadocManager javadocManager = JavadocManager.SERVICE.getInstance(tag.getProject());
|
||||
visitRefInDocTag(tag, javadocManager, context, problems, manager, onTheFly);
|
||||
}
|
||||
|
||||
@Override public void visitElement(PsiElement element) {
|
||||
PsiElement[] children = element.getChildren();
|
||||
for (PsiElement child : children) {
|
||||
//do not visit method javadoc twice
|
||||
if (!(child instanceof PsiDocCommentOwner)) {
|
||||
child.accept(this);
|
||||
if (word == null || StringUtil.isEmptyOrSpaces(word)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void visitRefInDocTag(final PsiDocTag tag,
|
||||
final JavadocManager manager,
|
||||
final PsiElement context,
|
||||
final ArrayList<ProblemDescriptor> problems,
|
||||
final InspectionManager inspectionManager,
|
||||
final boolean onTheFly) {
|
||||
final String tagName = tag.getName();
|
||||
final PsiDocTagValue value = tag.getValueElement();
|
||||
if (value == null) return;
|
||||
final JavadocTagInfo info = manager.getTagInfo(tagName);
|
||||
if (info != null && !info.isValidInContext(context)) return;
|
||||
final String message = info == null || !info.isInline() ? null : info.checkTagValue(value);
|
||||
if (message != null){
|
||||
problems.add(createDescriptor(value, message, inspectionManager, onTheFly));
|
||||
}
|
||||
|
||||
final PsiReference reference = value.getReference();
|
||||
if (reference == null) return;
|
||||
final PsiElement element = reference.resolve();
|
||||
if (element != null) return;
|
||||
final int textOffset = value.getTextOffset();
|
||||
if (textOffset == value.getTextRange().getEndOffset()) return;
|
||||
final PsiDocTagValue valueElement = tag.getValueElement();
|
||||
if (valueElement == null) return;
|
||||
|
||||
final CharSequence paramName = value.getContainingFile().getViewProvider().getContents().subSequence(textOffset, value.getTextRange().getEndOffset());
|
||||
final String params = "<code>" + paramName + "</code>";
|
||||
final List<LocalQuickFix> fixes = new ArrayList<LocalQuickFix>();
|
||||
if (onTheFly && "param".equals(tagName)) {
|
||||
final PsiDocCommentOwner commentOwner = PsiTreeUtil.getParentOfType(tag, PsiDocCommentOwner.class);
|
||||
if (commentOwner instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)commentOwner;
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
final PsiDocTag[] tags = tag.getContainingComment().getTags();
|
||||
final Set<String> unboundParams = new HashSet<String>();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!JavaDocLocalInspection.isFound(tags, parameter)) {
|
||||
unboundParams.add(parameter.getName());
|
||||
final List<LookupElement> items = new ArrayList<LookupElement>();
|
||||
for (String variant : myUnboundParams) {
|
||||
items.add(LookupElementBuilder.create(variant));
|
||||
}
|
||||
LookupManager.getInstance(project).showLookup(editor, items.toArray(new LookupElement[items.size()]));
|
||||
}
|
||||
if (!unboundParams.isEmpty()) {
|
||||
fixes.add(new RenameReferenceQuickFix(unboundParams));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
fixes.add(new RemoveTagFix(tagName, paramName));
|
||||
|
||||
problems.add(inspectionManager.createProblemDescriptor(valueElement, reference.getRangeInElement(), cannotResolveSymbolMessage(params),
|
||||
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly,
|
||||
fixes.toArray(new LocalQuickFix[fixes.size()])));
|
||||
}
|
||||
|
||||
private static String cannotResolveSymbolMessage(String params) {
|
||||
return InspectionsBundle.message("inspection.javadoc.problem.cannot.resolve", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionsBundle.message("inspection.javadoc.ref.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getGroupDisplayName() {
|
||||
return InspectionsBundle.message("group.names.javadoc.issues");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getShortName() {
|
||||
return SHORT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public HighlightDisplayLevel getDefaultLevel() {
|
||||
return HighlightDisplayLevel.ERROR;
|
||||
}
|
||||
|
||||
private class AddQualifierFix implements LocalQuickFix{
|
||||
@@ -294,79 +165,4 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class RenameReferenceQuickFix implements LocalQuickFix {
|
||||
private final Set<String> myUnboundParams;
|
||||
|
||||
public RenameReferenceQuickFix(Set<String> unboundParams) {
|
||||
myUnboundParams = unboundParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return "Change to ...";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
|
||||
final AsyncResult<DataContext> asyncResult = DataManager.getInstance().getDataContextFromFocus();
|
||||
asyncResult.doWhenDone(new AsyncResult.Handler<DataContext>() {
|
||||
@Override
|
||||
public void run(DataContext dataContext) {
|
||||
final Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
|
||||
assert editor != null;
|
||||
final TextRange textRange = ((ProblemDescriptorBase)descriptor).getTextRange();
|
||||
editor.getSelectionModel().setSelection(textRange.getStartOffset(), textRange.getEndOffset());
|
||||
|
||||
final String word = editor.getSelectionModel().getSelectedText();
|
||||
|
||||
if (word == null || StringUtil.isEmptyOrSpaces(word)) {
|
||||
return;
|
||||
}
|
||||
final List<LookupElement> items = new ArrayList<LookupElement>();
|
||||
for (String variant : myUnboundParams) {
|
||||
items.add(LookupElementBuilder.create(variant));
|
||||
}
|
||||
LookupManager.getInstance(project).showLookup(editor, items.toArray(new LookupElement[items.size()]));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static class RemoveTagFix implements LocalQuickFix {
|
||||
private final String myTagName;
|
||||
private final CharSequence myParamName;
|
||||
|
||||
public RemoveTagFix(String tagName, CharSequence paramName) {
|
||||
myTagName = tagName;
|
||||
myParamName = paramName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return "Remove @" + myTagName + " " + myParamName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiDocTag myTag = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiDocTag.class);
|
||||
if (myTag == null) return;
|
||||
if (!FileModificationService.getInstance().preparePsiElementForWrite(myTag)) return;
|
||||
myTag.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,16 @@ public class TypesDistinctProver {
|
||||
proveArrayTypeDistinct(((PsiWildcardType)type1).getManager().getProject(), (PsiArrayType)superBound, type2)) return true;
|
||||
|
||||
final PsiClass boundClass1 = PsiUtil.resolveClassInType(superBound);
|
||||
if (boundClass1 == null || boundClass1 instanceof PsiTypeParameter) return false;
|
||||
if (boundClass1 == null) return false;
|
||||
if (boundClass1 instanceof PsiTypeParameter) {
|
||||
final PsiClassType[] extendsListTypes = boundClass1.getExtendsListTypes();
|
||||
for (PsiClassType classType : extendsListTypes) {
|
||||
final PsiClass psiClass = classType.resolve();
|
||||
if (InheritanceUtil.isInheritorOrSelf(psiClass, psiClass2, true) || InheritanceUtil.isInheritorOrSelf(psiClass2, psiClass, true)) return false;
|
||||
}
|
||||
return extendsListTypes.length > 0;
|
||||
}
|
||||
|
||||
return !InheritanceUtil.isInheritorOrSelf(boundClass1, psiClass2, true);
|
||||
}
|
||||
|
||||
|
||||
+10
-5
@@ -579,12 +579,18 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
|
||||
return false;
|
||||
}
|
||||
|
||||
int leftStart = accessor.getParameterList().getTextRange().getEndOffset();
|
||||
int leftEnd = statement.getTextRange().getStartOffset();
|
||||
int rightStart = statement.getTextRange().getEndOffset();
|
||||
int rightEnd = body.getTextRange().getEndOffset();
|
||||
if (leftEnd <= leftStart + 1 || rightEnd <= rightStart + 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FoldingGroup group = FoldingGroup.newGroup("simple property accessor");
|
||||
int paramListEnd = accessor.getParameterList().getTextRange().getEndOffset();
|
||||
int statementStart = statement.getTextRange().getStartOffset();
|
||||
PsiJavaToken lBrace = body.getLBrace();
|
||||
assert lBrace != null;
|
||||
descriptorList.add(new FoldingDescriptor(lBrace.getNode(), new TextRange(paramListEnd, statementStart), group) {
|
||||
descriptorList.add(new FoldingDescriptor(lBrace.getNode(), new TextRange(leftStart, leftEnd), group) {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getPlaceholderText() {
|
||||
@@ -592,10 +598,9 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
|
||||
}
|
||||
});
|
||||
|
||||
int statementEnd = statement.getTextRange().getEndOffset();
|
||||
PsiJavaToken rBrace = body.getRBrace();
|
||||
assert rBrace != null;
|
||||
descriptorList.add(new FoldingDescriptor(rBrace.getNode(), new TextRange(statementEnd, body.getTextRange().getEndOffset()), group) {
|
||||
descriptorList.add(new FoldingDescriptor(rBrace.getNode(), new TextRange(rightStart, rightEnd), group) {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getPlaceholderText() {
|
||||
|
||||
@@ -898,7 +898,8 @@ public class ControlFlowUtil {
|
||||
|
||||
@Override
|
||||
public Boolean getResult() {
|
||||
return !maybeUnassigned[0];
|
||||
final int variableDeclarationOffset = flow.getStartOffset(variable.getParent());
|
||||
return !maybeUnassigned[variableDeclarationOffset > -1 ? variableDeclarationOffset : 0];
|
||||
}
|
||||
}
|
||||
if (flow.getSize() == 0) return false;
|
||||
|
||||
+2
-1
@@ -28,6 +28,7 @@ import com.intellij.util.ArrayUtilRt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -439,7 +440,7 @@ public class InferenceSession {
|
||||
if (lub != null) {
|
||||
inferenceVariable.setInstantiation(lub instanceof PsiCapturedWildcardType ? ((PsiCapturedWildcardType)lub).getWildcard() : lub);
|
||||
}
|
||||
else if (acceptObject || upperBounds.size() > 1) {
|
||||
else if (acceptObject || upperBounds.size() > 1 || !upperBounds.get(0).equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
|
||||
PsiType glb = null;
|
||||
for (PsiType upperBound : upperBounds) {
|
||||
upperBound = acceptBoundsWithRecursiveDependencies(typeParameter, upperBound, substitutor);
|
||||
|
||||
+2
-1
@@ -77,7 +77,8 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
final PsiExpressionList argumentList = ((PsiCallExpression)myExpression).getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final Pair<PsiMethod,PsiSubstitutor> pair = MethodCandidateInfo.getCurrentMethod(argumentList);
|
||||
final PsiMethod method = pair != null ? pair.first : ((PsiCallExpression)myExpression).resolveMethod();
|
||||
if (pair != null) return true;
|
||||
final PsiMethod method = ((PsiCallExpression)myExpression).resolveMethod();
|
||||
PsiType returnType = null;
|
||||
InferenceSession callSession = null;
|
||||
if (method != null) {
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
class A<T> {
|
||||
class B extends A<<error descr="B is not accessible in current context">B.B</error>>{}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
class A<T extends B.C>
|
||||
{
|
||||
interface C {}
|
||||
}
|
||||
|
||||
class B extends A<<error descr="C is not accessible in current context">B.C</error>>{}
|
||||
+11
-1
@@ -243,4 +243,14 @@ class IDEA89640 {
|
||||
boolean flag = a != b;
|
||||
System.out.println(flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Parametrized<<warning descr="Type parameter 'T' is never used">T</warning> extends Number> {
|
||||
class Bug1<T extends java.io.Serializable> {
|
||||
void bug1(Parametrized<? super T> <warning descr="Parameter 'param' is never used">param</warning>) {}
|
||||
}
|
||||
|
||||
class Bug2<T extends String> {
|
||||
void bug1(Parametrized<<error descr="Type parameter '? super T' is not within its bound; should extend 'java.lang.Number'">? super T</error>> <warning descr="Parameter 'param' is never used">param</warning>) {}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-1
@@ -114,4 +114,17 @@ class ParameterIsEffectivelyFinal {
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class IDEA114737 {
|
||||
private void on(String propertyName) {
|
||||
if (!"taskServices".equals(propertyName)) {
|
||||
return;
|
||||
}
|
||||
java.util.List<String> newList = null;
|
||||
Comparable<String> c1 = o -> {
|
||||
System.out.println(newList);
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import java.util.*;
|
||||
abstract class IX<T> {
|
||||
/**
|
||||
* @param t the param
|
||||
*/
|
||||
abstract void foo(T t){}
|
||||
}
|
||||
|
||||
class XXC extends IX<List<String>> {
|
||||
/**
|
||||
* @param strings the param
|
||||
*/
|
||||
@Override
|
||||
void foo(List<String> strings) {
|
||||
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import java.util.*;
|
||||
abstract class IX<T> {
|
||||
/**
|
||||
* @param t the param
|
||||
*/
|
||||
abstract void foo(T t){}
|
||||
}
|
||||
|
||||
class XXC extends IX<List<String>> {
|
||||
<caret>
|
||||
}
|
||||
@@ -51,6 +51,7 @@ public class OverrideImplementTest extends LightCodeInsightTestCase {
|
||||
|
||||
public void testSimple() { doTest(true); }
|
||||
public void testAnnotation() { doTest(true); }
|
||||
public void testJavadocForChangedParamName() { doTest(true); }
|
||||
public void testIncomplete() { doTest(false); }
|
||||
public void testSubstitutionInTypeParametersList() { doTest(false); }
|
||||
public void testTestMissed() { doTest(false); }
|
||||
|
||||
@@ -23,8 +23,12 @@ import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import com.intellij.codeInsight.lookup.LookupManager
|
||||
import com.intellij.codeInsight.lookup.PsiTypeLookupItem
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl
|
||||
import com.intellij.codeInsight.template.JavaCodeContextType
|
||||
import com.intellij.codeInsight.template.LiveTemplateTest
|
||||
import com.intellij.codeInsight.template.Template
|
||||
import com.intellij.codeInsight.template.TemplateContextType
|
||||
import com.intellij.codeInsight.template.TemplateManager
|
||||
import com.intellij.codeInsight.template.impl.TemplateImpl
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
||||
import com.intellij.ide.DataManager
|
||||
import com.intellij.ide.ui.UISettings
|
||||
@@ -49,6 +53,7 @@ import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiJavaFile
|
||||
import com.intellij.psi.statistics.StatisticsManager
|
||||
import com.intellij.psi.statistics.impl.StatisticsManagerImpl
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
@@ -1520,4 +1525,28 @@ class X extends Foo {
|
||||
assert lookup
|
||||
}
|
||||
|
||||
public void "test live template without description"() {
|
||||
final TemplateManager manager = TemplateManager.getInstance(getProject());
|
||||
final Template template = manager.createTemplate("tpl", "user", null);
|
||||
final JavaCodeContextType contextType =
|
||||
ContainerUtil.findInstance(TemplateContextType.EP_NAME.getExtensions(), JavaCodeContextType.Statement);
|
||||
((TemplateImpl)template).getTemplateContext().setEnabled(contextType, true);
|
||||
LiveTemplateTest.addTemplate(template, testRootDisposable)
|
||||
|
||||
myFixture.configureByText 'a.java', '''
|
||||
class Foo {
|
||||
int tplMn;
|
||||
|
||||
{ <caret> }
|
||||
}
|
||||
'''
|
||||
type 'tpl'
|
||||
myFixture.assertPreferredCompletionItems 0, 'tplMn', 'tpl'
|
||||
|
||||
LookupElementPresentation p = LookupElementPresentation.renderElement(myFixture.lookupElements[1])
|
||||
assert p.itemText == 'tpl'
|
||||
assert !p.tailText
|
||||
assert p.typeText == ' [Tab] '
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-12
@@ -5,12 +5,8 @@ import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation;
|
||||
import com.intellij.codeInsight.template.SmartCompletionContextType;
|
||||
import com.intellij.codeInsight.template.Template;
|
||||
import com.intellij.codeInsight.template.TemplateContextType;
|
||||
import com.intellij.codeInsight.template.TemplateManager;
|
||||
import com.intellij.codeInsight.template.*;
|
||||
import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateSettings;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
@@ -650,13 +646,8 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
|
||||
final SmartCompletionContextType completionContextType =
|
||||
ContainerUtil.findInstance(TemplateContextType.EP_NAME.getExtensions(), SmartCompletionContextType.class);
|
||||
((TemplateImpl)template).getTemplateContext().setEnabled(completionContextType, true);
|
||||
TemplateSettings.getInstance().addTemplate(template);
|
||||
try {
|
||||
doTest();
|
||||
}
|
||||
finally {
|
||||
TemplateSettings.getInstance().removeTemplate(template);
|
||||
}
|
||||
LiveTemplateTest.addTemplate(template, myTestRootDisposable);
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testInThisExpression() throws Throwable { doTest(); }
|
||||
|
||||
@@ -316,6 +316,8 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testIDEA87860() throws Exception { doTest5(false); }
|
||||
public void testIDEA67584() throws Exception { doTest5(false); }
|
||||
public void testIDEA113225() throws Exception { doTest5(false); }
|
||||
public void testIDEA67518() throws Exception { doTest5(false); }
|
||||
public void testIDEA57252() throws Exception { doTest5(false); }
|
||||
|
||||
public void testJavaUtilCollections_NoVerify() throws Exception {
|
||||
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: cdr
|
||||
* Date: Jul 31, 2007
|
||||
* Time: 2:39:56 PM
|
||||
*/
|
||||
package com.intellij.codeInsight.daemon;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.ex.InspectionToolRegistrar;
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
|
||||
import com.intellij.codeInspection.unusedImport.UnusedImportLocalInspection;
|
||||
import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiManagerEx;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PsiShortNamesCache;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class HighlightStressTest extends LightDaemonAnalyzerTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
if ("RandomEditingForUnused".equals(getTestName(false))) {
|
||||
return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UnusedImportLocalInspection(),};
|
||||
}
|
||||
List<InspectionToolWrapper> all = InspectionToolRegistrar.getInstance().createTools();
|
||||
List<LocalInspectionTool> locals = new ArrayList<LocalInspectionTool>();
|
||||
for (InspectionToolWrapper tool : all) {
|
||||
if (tool instanceof LocalInspectionToolWrapper) {
|
||||
LocalInspectionTool e = ((LocalInspectionToolWrapper)tool).getTool();
|
||||
locals.add(e);
|
||||
}
|
||||
}
|
||||
return locals.toArray(new LocalInspectionTool[locals.size()]);
|
||||
}
|
||||
|
||||
@NonNls private static final String text = "import java.util.*; class X { void f ( ) { "
|
||||
+ "List < String > ls = new ArrayList < String > ( 1 ) ; ls . toString ( ) ; \n"
|
||||
+ "List < Integer > is = new ArrayList < Integer > ( 1 ) ; is . toString ( ) ; \n"
|
||||
+ "List i = new ArrayList ( 1 ) ; i . toString ( ) ; \n"
|
||||
+ "Collection < Number > l2 = new ArrayList < Number > ( 10 ) ; l2 . toString ( ) ; \n"
|
||||
+ "Collection < Number > l22 = new ArrayList < Number > ( ) ; l22 . toString ( ) ; \n"
|
||||
+ "Map < Number , String > l3 = new HashMap < Number , String > ( 10 ) ; l3 . toString ( ) ; \n"
|
||||
+ "Map < String , String > m = new HashMap < String , String > ( ) ; m . toString ( ) ; \n"
|
||||
+ "Map < String , String > m1 = new HashMap < String , String > ( ) ; m1 . toString ( ) ; \n"
|
||||
+ "Map < String , String > m2 = new HashMap < String , String > ( ) ; m2 . toString ( ) ; \n"
|
||||
+ "Map < String , String > m3 = new HashMap < String , String > ( ) ; m3 . toString ( ) ; \n"
|
||||
+ "Map < String , String > mi = new HashMap < String , String > ( 1 ) ; mi . toString ( ) ; \n"
|
||||
+ "Map < String , String > mi1 = new HashMap < String , String > ( 1 ) ; mi1 . toString ( ) ; \n"
|
||||
+ "Map < String , String > mi2 = new HashMap < String , String > ( 1 ) ; mi2 . toString ( ) ; \n"
|
||||
+ "Map < String , String > mi3 = new HashMap < String , String > ( 1 ) ; mi3 . toString ( ) ; \n"
|
||||
+ "Map < Number , String > l4 = new HashMap < Number , String > ( ) ; l4 . toString ( ) ; \n"
|
||||
+ "Map < Number , String > l5 = new HashMap < Number , String > ( l4 ) ; l5 . toString ( ) ; \n"
|
||||
+ "HashMap < Number , String > l6 = new HashMap < Number , String > ( ) ; l6 . toString ( ) ; \n"
|
||||
+ "Map < List < Integer > , Map < String , List < String > > > l7 = new HashMap ( 1 ) ; l7 . toString ( ) ; \n"
|
||||
+ "java . util . Map < java . util . List < Integer > , java . util . Map < String , java . util . List < String > > > l77 = new java . util . HashMap ( 1 ) ; l77 . toString ( ) ; \n"
|
||||
+ " } } ";
|
||||
|
||||
public void testAllTheseConcurrentThreadsDoNotCrashAnything() throws Exception {
|
||||
long time = System.currentTimeMillis();
|
||||
for (int i = 0; i < 20/*00000*/; i++) {
|
||||
//System.out.println("i = " + i);
|
||||
getPsiManager().dropResolveCaches();
|
||||
((PsiManagerEx)getPsiManager()).getFileManager().cleanupForNextTest();
|
||||
DaemonCodeAnalyzer.getInstance(getProject()).restart();
|
||||
|
||||
configureFromFileText("Stress.java", text);
|
||||
List<HighlightInfo> infos = doHighlighting();
|
||||
assertEmpty(DaemonAnalyzerTestCase.filter(infos, HighlightSeverity.ERROR));
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
FileEditorManagerEx.getInstanceEx(getProject()).closeAllFiles();
|
||||
}
|
||||
System.out.println(System.currentTimeMillis() - time+"ms");
|
||||
}
|
||||
|
||||
public void _testHugeFile() throws Exception {
|
||||
@NonNls String filePath = "/psi/resolve/Thinlet.java";
|
||||
configureByFile(filePath);
|
||||
doHighlighting();
|
||||
|
||||
int N = 42;
|
||||
long[] time = new long[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
DaemonCodeAnalyzer.getInstance(getProject()).restart();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
doHighlighting();
|
||||
long end = System.currentTimeMillis();
|
||||
time[i] = end - start;
|
||||
System.out.println("i = " + i + "; time= "+(end-start));
|
||||
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
}
|
||||
System.out.println("Average among the N/3 median times: " + PlatformTestUtil.averageAmongMedians(time, 3) + "ms");
|
||||
|
||||
//System.out.println("JobLauncher.COUNT = " + JobLauncher.COUNT);
|
||||
//System.out.println("JobLauncher.TINY = " + JobLauncher.TINY_COUNT);
|
||||
//System.out.println("JobLauncher.LENGTH = " + JobLauncher.LENGTH);
|
||||
//System.out.println("JobLauncher.ELAPSED = " + JobLauncher.ELAPSED);
|
||||
//System.out.println("Ave length : "+(JobLauncher.LENGTH.get()/1.0/JobLauncher.COUNT.get()));
|
||||
//System.out.println("Ave elapsed: "+(JobLauncher.ELAPSED.get()/1.0/JobLauncher.COUNT.get()));
|
||||
//
|
||||
//JobLauncher.lengths.sort();
|
||||
//System.out.println("Lengths: "+JobLauncher.lengths);
|
||||
}
|
||||
|
||||
public void testRandomEditingPerformance() throws Exception {
|
||||
configureFromFileText("Stress.java", text);
|
||||
List<HighlightInfo> list = doHighlighting();
|
||||
int warnings = list.size();
|
||||
Random random = new Random();
|
||||
|
||||
DaemonCodeAnalyzer.getInstance(getProject()).restart();
|
||||
int N = 20;
|
||||
long[] time = new long[N];
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
System.out.println("i = " + i);
|
||||
String s = myFile.getText();
|
||||
int offset;
|
||||
while (true) {
|
||||
offset = random.nextInt(s.length());
|
||||
if (s.charAt(offset) == ' ') break;
|
||||
}
|
||||
myEditor.getCaretModel().moveToOffset(offset);
|
||||
type("/*--*/");
|
||||
Collection<HighlightInfo> infos = doHighlighting();
|
||||
if (warnings != infos.size()) {
|
||||
list = new ArrayList<HighlightInfo>(list);
|
||||
Collections.sort(list, new Comparator<HighlightInfo>() {
|
||||
@Override
|
||||
public int compare(HighlightInfo o1, HighlightInfo o2) {
|
||||
if (o1.equals(o2)) return 0;
|
||||
if (o1.getActualStartOffset() != o2.getActualStartOffset()) return o1.getActualStartOffset() - o2.getActualStartOffset();
|
||||
return (o1.getText() + o1.getDescription()).compareTo(o2.getText() + o2.getDescription());
|
||||
}
|
||||
});
|
||||
infos = new ArrayList<HighlightInfo>(infos);
|
||||
Collections.sort((ArrayList<HighlightInfo>)infos, new Comparator<HighlightInfo>() {
|
||||
@Override
|
||||
public int compare(HighlightInfo o1, HighlightInfo o2) {
|
||||
if (o1.equals(o2)) return 0;
|
||||
if (o1.getActualStartOffset() != o2.getActualStartOffset()) return o1.getActualStartOffset() - o2.getActualStartOffset();
|
||||
return (o1.getText() + o1.getDescription()).compareTo(o2.getText() + o2.getDescription());
|
||||
}
|
||||
});
|
||||
System.out.println(">--------------------");
|
||||
for (HighlightInfo info : list) {
|
||||
System.out.println(info);
|
||||
}
|
||||
System.out.println("---------------------");
|
||||
for (HighlightInfo info : infos) {
|
||||
System.out.println(info);
|
||||
}
|
||||
System.out.println("<--------------------");
|
||||
}
|
||||
assertEquals(infos.toString(), warnings, infos.size());
|
||||
for (HighlightInfo info : infos) {
|
||||
assertNotSame(info + "", HighlightSeverity.ERROR, info.getSeverity());
|
||||
}
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
time[i] = end - start;
|
||||
}
|
||||
FileEditorManagerEx.getInstanceEx(getProject()).closeAllFiles();
|
||||
|
||||
System.out.println("Average among the N/3 median times: " + PlatformTestUtil.averageAmongMedians(time, 3) + "ms");
|
||||
}
|
||||
|
||||
public void testRandomEditingForUnused() throws Exception {
|
||||
configureFromFileText("Stress.java", "class X {<caret>}");
|
||||
|
||||
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(getProject());
|
||||
String[] names = cache.getAllClassNames();
|
||||
|
||||
final StringBuilder imports = new StringBuilder();
|
||||
final StringBuilder usages = new StringBuilder();
|
||||
int v = 0;
|
||||
List<PsiClass> aclasses = new ArrayList<PsiClass>();
|
||||
for (String name : names) {
|
||||
PsiClass[] classes = cache.getClassesByName(name, GlobalSearchScope.allScope(getProject()));
|
||||
if (classes.length == 0) continue;
|
||||
PsiClass aClass = classes[0];
|
||||
if (!aClass.hasModifierProperty(PsiModifier.PUBLIC)) continue;
|
||||
if (aClass.getSuperClass() == null) continue;
|
||||
PsiClassType[] superTypes = aClass.getSuperTypes();
|
||||
if (superTypes.length == 0 || superTypes[0].resolve() == null) continue;
|
||||
String qualifiedName = aClass.getQualifiedName();
|
||||
if (qualifiedName.startsWith("java.lang.invoke")) continue; // java.lang.invoke.MethodHandle has weird access attributes in recent rt.jar which causes spurious highlighting errors
|
||||
imports.append("import " + qualifiedName + ";\n");
|
||||
usages.append("/**/ "+aClass.getName() + " var" + v + " = null; var" + v + ".toString();\n");
|
||||
aclasses.add(aClass);
|
||||
v++;
|
||||
if (v>100) break;
|
||||
}
|
||||
final String text = imports + "\n class X {{\n" + usages + "}}";
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
getEditor().getDocument().setText(text);
|
||||
}
|
||||
});
|
||||
|
||||
List<HighlightInfo> errors = DaemonAnalyzerTestCase.filter(doHighlighting(), HighlightSeverity.WARNING);
|
||||
assertEmpty(errors);
|
||||
Random random = new Random();
|
||||
int unused = 0;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
String s = myFile.getText();
|
||||
|
||||
int offset;
|
||||
while (true) {
|
||||
offset = random.nextInt(s.length());
|
||||
if (CharArrayUtil.regionMatches(s, offset, "/**/") || CharArrayUtil.regionMatches(s, offset, "//")) break;
|
||||
}
|
||||
|
||||
char next = offset < s.length()-1 ? s.charAt(offset+1) : 0;
|
||||
if (next == '/') {
|
||||
myEditor.getCaretModel().moveToOffset(offset + 1);
|
||||
type("**");
|
||||
unused--;
|
||||
}
|
||||
else if (next == '*') {
|
||||
myEditor.getCaretModel().moveToOffset(offset + 1);
|
||||
delete();
|
||||
delete();
|
||||
unused++;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
|
||||
getFile().accept(new PsiRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
assertTrue(element.toString(), element.isValid());
|
||||
super.visitElement(element);
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println("i = " + i + " " + next + " at "+offset);
|
||||
|
||||
List<HighlightInfo> infos = doHighlighting();
|
||||
errors = DaemonAnalyzerTestCase.filter(infos, HighlightSeverity.ERROR);
|
||||
assertEmpty(errors);
|
||||
List<HighlightInfo> warns = DaemonAnalyzerTestCase.filter(infos, HighlightSeverity.WARNING);
|
||||
if (unused != warns.size()) {
|
||||
assertEquals(warns.toString(), unused, warns.size());
|
||||
}
|
||||
}
|
||||
FileEditorManagerEx.getInstanceEx(getProject()).closeAllFiles();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.daemon;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator;
|
||||
import com.intellij.concurrency.JobLauncher;
|
||||
import com.intellij.concurrency.JobSchedulerImpl;
|
||||
import com.intellij.concurrency.SensitiveProgressWrapper;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
import com.intellij.testFramework.PlatformTestCase;
|
||||
import com.intellij.util.Processor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class JobUtilTest extends PlatformTestCase {
|
||||
@Override
|
||||
protected boolean isRunInWriteAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testUnbalancedTaskJobUtilPerformance() {
|
||||
List<Integer> things = new ArrayList<Integer>(Collections.<Integer>nCopies(10000, null));
|
||||
int sum = 0;
|
||||
for (int i = 0; i < things.size(); i++) {
|
||||
int v = i < 9950 ? 1 : 1000;
|
||||
things.set(i, v);
|
||||
sum += things.get(i);
|
||||
}
|
||||
assertEquals(59950, sum);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
boolean b = JobLauncher.getInstance().invokeConcurrentlyUnderProgress(things, new ProgressIndicatorBase(), false, false, new Processor<Integer>() {
|
||||
@Override
|
||||
public boolean process(Integer o) {
|
||||
busySleep(o);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
assertTrue(b);
|
||||
long elapsed = System.currentTimeMillis() - start;
|
||||
int expected = 2 * (9950 + 50 * 1000) / JobSchedulerImpl.CORES_COUNT;
|
||||
String message = "Elapsed: " + elapsed + "; expected: " + expected;
|
||||
System.out.println(message);
|
||||
assertTrue(message, elapsed < expected);
|
||||
}
|
||||
private static final AtomicInteger COUNT = new AtomicInteger();
|
||||
|
||||
private static int busySleep(int ms) {
|
||||
long end = System.currentTimeMillis() + ms;
|
||||
while (System.currentTimeMillis() < end);
|
||||
return COUNT.incrementAndGet();
|
||||
}
|
||||
|
||||
public void testJobUtilFinishes() throws Exception {
|
||||
COUNT.set(0);
|
||||
int N = 100000;
|
||||
List<String> list = Collections.nCopies(N, null);
|
||||
final AtomicReference<Exception> exception = new AtomicReference<Exception>();
|
||||
final AtomicBoolean finished = new AtomicBoolean();
|
||||
|
||||
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(list, null, false, new Processor<String>() {
|
||||
@Override
|
||||
public boolean process(String name) {
|
||||
try {
|
||||
if (finished.get()) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
new BigDecimal(i).multiply(new BigDecimal(1));
|
||||
}
|
||||
busySleep(1);
|
||||
if (finished.get()) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
exception.set(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
finished.set(true);
|
||||
Thread.sleep(1000);
|
||||
if (exception.get() != null) throw exception.get();
|
||||
assertEquals(N, COUNT.get());
|
||||
}
|
||||
|
||||
public void testJobUtilProcessesAllItems() throws Exception {
|
||||
List<String> list = Collections.nCopies(10000, null);
|
||||
final AtomicReference<Exception> exception = new AtomicReference<Exception>();
|
||||
for (int i=0; i<10; i++) {
|
||||
long start = System.currentTimeMillis();
|
||||
COUNT.set(0);
|
||||
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(list, null, false, new Processor<String>() {
|
||||
@Override
|
||||
public boolean process(String name) {
|
||||
busySleep(1);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (exception.get() != null) throw exception.get();
|
||||
long finish = System.currentTimeMillis();
|
||||
System.out.println("Elapsed: "+(finish-start)+"ms");
|
||||
assertEquals(list.size(), COUNT.get());
|
||||
}
|
||||
}
|
||||
|
||||
public void testJobUtilRecursive() throws Exception {
|
||||
final List<String> list = Collections.nCopies(100, null);
|
||||
for (int i=0; i<10; i++) {
|
||||
COUNT.set(0);
|
||||
long start = System.currentTimeMillis();
|
||||
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(list, null, false, new Processor<String>() {
|
||||
@Override
|
||||
public boolean process(String name) {
|
||||
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(list, null, false, new Processor<String>() {
|
||||
@Override
|
||||
public boolean process(String name) {
|
||||
busySleep(1);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
long finish = System.currentTimeMillis();
|
||||
System.out.println("Elapsed: "+(finish-start)+"ms");
|
||||
assertEquals(list.size()*list.size(), COUNT.get());
|
||||
}
|
||||
}
|
||||
|
||||
public void testCorrectProgressAndReadAction() throws Throwable {
|
||||
checkProgressAndReadAction(Collections.singletonList(null), new DaemonProgressIndicator(), true);
|
||||
checkProgressAndReadAction(Collections.singletonList(null), new DaemonProgressIndicator(), false);
|
||||
checkProgressAndReadAction(Collections.emptyList(), new DaemonProgressIndicator(), true);
|
||||
checkProgressAndReadAction(Collections.emptyList(), new DaemonProgressIndicator(), false);
|
||||
checkProgressAndReadAction(Arrays.asList(new Object(), new Object()), new DaemonProgressIndicator(), true);
|
||||
checkProgressAndReadAction(Arrays.asList(new Object(), new Object()), new DaemonProgressIndicator(), false);
|
||||
checkProgressAndReadAction(Arrays.asList(new Object(), new Object()), null, false);
|
||||
}
|
||||
|
||||
private static void checkProgressAndReadAction(final List<Object> objects,
|
||||
final DaemonProgressIndicator progress,
|
||||
final boolean runInReadAction) throws Throwable {
|
||||
final AtomicReference<Throwable> exception = new AtomicReference<Throwable>();
|
||||
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(objects, progress, runInReadAction, new Processor<Object>() {
|
||||
@Override
|
||||
public boolean process(Object o) {
|
||||
try {
|
||||
if (objects.size() <= 1 || JobSchedulerImpl.CORES_COUNT <= 2) {
|
||||
assertTrue(ApplicationManager.getApplication().isDispatchThread());
|
||||
}
|
||||
else {
|
||||
// generally we know nothing about current thread since FJP can help others task to execute while in current context
|
||||
}
|
||||
ProgressIndicator actualIndicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (progress == null) {
|
||||
assertNotNull(actualIndicator);
|
||||
assertTrue(actualIndicator instanceof ProgressIndicatorBase);
|
||||
}
|
||||
else {
|
||||
assertTrue(actualIndicator instanceof SensitiveProgressWrapper);
|
||||
ProgressIndicator original = ((SensitiveProgressWrapper)actualIndicator).getOriginalProgressIndicator();
|
||||
assertSame(progress, original);
|
||||
}
|
||||
// there can be read access even if we didn't ask for it (e.g. when task under read action steals others work)
|
||||
assertTrue(!runInReadAction || ApplicationManager.getApplication().isReadAccessAllowed());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
exception.set(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (exception.get() != null) throw exception.get();
|
||||
}
|
||||
|
||||
public void testExceptionalCompletion() throws Throwable {
|
||||
final List<Object> objects = Collections.nCopies(100000000, null);
|
||||
COUNT.set(0);
|
||||
try {
|
||||
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(objects, null, true, new Processor<Object>() {
|
||||
@Override
|
||||
public boolean process(Object o) {
|
||||
if (COUNT.incrementAndGet() == 100000) {
|
||||
System.out.println("PCE");
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
fail("PCE must have been thrown");
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
// caught OK
|
||||
}
|
||||
}
|
||||
public void testNotNormalCompletion() throws Throwable {
|
||||
final List<Object> objects = Collections.nCopies(100000000, null);
|
||||
COUNT.set(0);
|
||||
boolean success = JobLauncher.getInstance().invokeConcurrentlyUnderProgress(objects, null, true, new Processor<Object>() {
|
||||
@Override
|
||||
public boolean process(Object o) {
|
||||
if (COUNT.incrementAndGet() == 100000) {
|
||||
System.out.println("PCE");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
assertFalse(success);
|
||||
}
|
||||
|
||||
public void testJobUtilCompletesEvenIfCannotGrabReadAction() throws Throwable {
|
||||
final List<Object> objects = Collections.nCopies(1000000, null);
|
||||
COUNT.set(0);
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
boolean success = JobLauncher.getInstance().invokeConcurrentlyUnderProgress(objects, null, true, false, new Processor<Object>() {
|
||||
@Override
|
||||
public boolean process(Object o) {
|
||||
COUNT.incrementAndGet();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
assertTrue(success);
|
||||
assertEquals(objects.size(), COUNT.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testJobUtilRecursiveCancel() throws Exception {
|
||||
final List<String> list = Collections.nCopies(100, "");
|
||||
final List<Integer> ilist = Collections.nCopies(100, 0);
|
||||
for (int i=0; i<1/*0*/; i++) {
|
||||
COUNT.set(0);
|
||||
long start = System.currentTimeMillis();
|
||||
boolean success = false;
|
||||
try {
|
||||
success = JobLauncher.getInstance().invokeConcurrentlyUnderProgress(list, null, false, new Processor<String>() {
|
||||
@Override
|
||||
public boolean process(String name) {
|
||||
boolean nestedSuccess = JobLauncher.getInstance().invokeConcurrentlyUnderProgress(ilist, null, false, new Processor<Integer>() {
|
||||
@Override
|
||||
public boolean process(Integer integer) {
|
||||
if (busySleep(1) == 1000) {
|
||||
System.out.println("PCE");
|
||||
throw new RuntimeException("xxx");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
System.out.println("nestedSuccess = " + nestedSuccess);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
// OK
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
assertEquals("xxx", e.getMessage());
|
||||
}
|
||||
long finish = System.currentTimeMillis();
|
||||
System.out.println("Elapsed: "+(finish-start)+"ms");
|
||||
//assertEquals(list.size()*list.size(), COUNT.get());
|
||||
assertFalse(success);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -434,6 +434,7 @@ class Test {
|
||||
public void "test simple property accessors in one line"() {
|
||||
configure """class Foo {
|
||||
int field;
|
||||
int field2;
|
||||
|
||||
int getField()
|
||||
{
|
||||
@@ -443,11 +444,13 @@ class Test {
|
||||
void setField(int f) {
|
||||
field = f;
|
||||
}
|
||||
|
||||
void setField2(int f){field2=f;}
|
||||
|
||||
}"""
|
||||
PsiClass fooClass = JavaPsiFacade.getInstance(project).findClass('Foo', GlobalSearchScope.allScope(project))
|
||||
def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset }
|
||||
assert regions.size() == 4
|
||||
assert regions.size() == 5
|
||||
|
||||
Closure checkAccessorFolding = { FoldRegion region1, FoldRegion region2, PsiMethod method ->
|
||||
assert region1.startOffset == method.parameterList.textRange.endOffset
|
||||
@@ -463,6 +466,7 @@ class Test {
|
||||
checkAccessorFolding(regions[0], regions[1], fooClass.methods[0])
|
||||
checkAccessorFolding(regions[2], regions[3], fooClass.methods[1])
|
||||
|
||||
assert regions[4].placeholderText == '{...}'
|
||||
}
|
||||
|
||||
private def changeFoldRegions(Closure op) {
|
||||
|
||||
@@ -1,31 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2005 JetBrains s.r.o. All Rights Reserved.
|
||||
*/
|
||||
package com.intellij.codeInsight.template;
|
||||
|
||||
package com.intellij.codeInsight.template
|
||||
|
||||
import com.intellij.JavaTestUtil
|
||||
import com.intellij.codeInsight.CodeInsightSettings
|
||||
import com.intellij.codeInsight.lookup.LookupManager
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl
|
||||
import com.intellij.codeInsight.lookup.impl.LookupManagerImpl
|
||||
import com.intellij.codeInsight.template.impl.*
|
||||
import com.intellij.codeInsight.template.macro.ClassNameCompleteMacro
|
||||
import com.intellij.codeInsight.template.macro.CompleteMacro
|
||||
import com.intellij.codeInsight.template.macro.MethodReturnTypeMacro
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.AccessToken
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.impl.DocumentImpl
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import com.intellij.codeInsight.template.impl.*
|
||||
|
||||
import static com.intellij.codeInsight.template.Template.Property.*
|
||||
import static com.intellij.codeInsight.template.Template.Property.USE_STATIC_IMPORT_IF_POSSIBLE
|
||||
|
||||
/**
|
||||
* @author spleaner
|
||||
@@ -65,19 +66,11 @@ public class LiveTemplateTest extends LightCodeInsightFixtureTestCase {
|
||||
final TemplateContextType contextType =
|
||||
ContainerUtil.findInstance(TemplateContextType.EP_NAME.getExtensions(), JavaCodeContextType.class);
|
||||
((TemplateImpl)template).getTemplateContext().setEnabled(contextType, true);
|
||||
TemplateSettings settings = TemplateSettings.getInstance();
|
||||
try {
|
||||
settings.addTemplate(template);
|
||||
final Editor editor = getEditor();
|
||||
addTemplate(template, testRootDisposable)
|
||||
final Editor editor = getEditor();
|
||||
|
||||
manager.startTemplate(editor, settings.getDefaultShortcutChar());
|
||||
checkResultByText(expected);
|
||||
}
|
||||
finally {
|
||||
if (settings.getTemplate(template.getKey(), group) != null) {
|
||||
settings.removeTemplate(template);
|
||||
}
|
||||
}
|
||||
manager.startTemplate(editor, (char)'\t');
|
||||
checkResultByText(expected);
|
||||
}
|
||||
|
||||
public void testTemplateWithArg1() throws IOException {
|
||||
@@ -559,15 +552,15 @@ class Foo {
|
||||
|
||||
myFixture.configureByText("a.java", "class A { void f() { Stri<selection>ng s = \"tpl</selection><caret>\"; } }")
|
||||
|
||||
addTemplate(template, testRootDisposable)
|
||||
myFixture.type '\t'
|
||||
myFixture.checkResult 'class A { void f() { Stri "; } }'
|
||||
}
|
||||
|
||||
static void addTemplate(Template template, Disposable parentDisposable) {
|
||||
def settings = TemplateSettings.getInstance()
|
||||
settings.addTemplate(template);
|
||||
try {
|
||||
myFixture.type '\t'
|
||||
myFixture.checkResult 'class A { void f() { Stri "; } }'
|
||||
}
|
||||
finally {
|
||||
settings.removeTemplate(template);
|
||||
}
|
||||
Disposer.register(parentDisposable, { settings.removeTemplate(template) } as Disposable)
|
||||
}
|
||||
|
||||
public void "test expand current live template on no suggestions in lookup"() {
|
||||
|
||||
+2
-2
@@ -109,8 +109,8 @@ class DependencyContext {
|
||||
myEnumerator.force();
|
||||
}
|
||||
|
||||
public Logger<Integer> getLogger(final com.intellij.openapi.diagnostic.Logger log) {
|
||||
return new Logger<Integer>() {
|
||||
public LoggerWrapper<Integer> getLogger(final com.intellij.openapi.diagnostic.Logger log) {
|
||||
return new LoggerWrapper<Integer>() {
|
||||
@Override
|
||||
public void debug(String comment, Integer s) {
|
||||
if (log.isDebugEnabled()) {
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ package org.jetbrains.jps.builders.java.dependencyView;
|
||||
* @author: db
|
||||
* Date: 20.01.12
|
||||
*/
|
||||
public interface Logger<T> {
|
||||
public interface LoggerWrapper<T> {
|
||||
void debug(String comment, T t);
|
||||
void debug(String comment, String t);
|
||||
void debug(String comment, boolean t);
|
||||
@@ -72,7 +72,7 @@ public class Mappings {
|
||||
private final int myInitName;
|
||||
private final int myEmptyName;
|
||||
private final int myObjectClassName;
|
||||
private org.jetbrains.jps.builders.java.dependencyView.Logger<Integer> myDebugS;
|
||||
private LoggerWrapper<Integer> myDebugS;
|
||||
|
||||
private IntIntMultiMaplet myClassToSubclasses;
|
||||
|
||||
|
||||
@@ -24,8 +24,10 @@ import org.jetbrains.jps.cmdline.ClasspathBootstrap;
|
||||
import org.jetbrains.jps.incremental.LineOutputWriter;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -71,7 +73,17 @@ public class JavacMain {
|
||||
if (compiler == null) {
|
||||
compiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (compiler == null) {
|
||||
diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "System Java Compiler was not found in classpath"));
|
||||
String message = "System Java Compiler was not found in classpath";
|
||||
// trying to obtain additional diagnostic for the case when compiler.jar is present, but there were problems with compiler class loading:
|
||||
try {
|
||||
Class.forName("com.sun.tools.javac.api.JavacTool", false, JavacMain.class.getClassLoader());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ex.printStackTrace(new PrintStream(out));
|
||||
message = message + ":\n" + out.toString();
|
||||
}
|
||||
diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, message));
|
||||
return false;
|
||||
}
|
||||
nowUsingJavac = true;
|
||||
|
||||
@@ -86,6 +86,9 @@ public class JavacServerBootstrap {
|
||||
appendParam(cmdLine, "-D" + JavacServer.USE_ECLIPSE_COMPILER_PROPERTY);
|
||||
}
|
||||
|
||||
// this will disable standard extensions to ensure javac is loaded from the right tools.jar
|
||||
appendParam(cmdLine, "-Djava.ext.dirs=");
|
||||
|
||||
for (String option : vmOptions) {
|
||||
appendParam(cmdLine, option);
|
||||
}
|
||||
|
||||
Binary file not shown.
+11
-10
@@ -2,12 +2,13 @@ asm-commons.jar
|
||||
asm.jar
|
||||
asm4-all.jar
|
||||
automaton.jar
|
||||
cli-parser-1.1.jar
|
||||
cglib-2.2.2.jar
|
||||
cli-parser-1.1.jar
|
||||
commons-codec-1.3.jar
|
||||
commons-httpclient-3.1-patched.jar
|
||||
commons-logging-1.1.1.jar
|
||||
commons-net-3.1.jar
|
||||
ecj-4.2.1.jar
|
||||
groovy-all-2.0.6.jar
|
||||
gson-2.2.3.jar
|
||||
guava-14.0.1.jar
|
||||
@@ -15,29 +16,34 @@ jaxen-1.1.3.jar
|
||||
jayatana-1.2.4.jar
|
||||
jcip-annotations.jar
|
||||
jdom.jar
|
||||
jgoodies-common-1.2.1.jar
|
||||
jgoodies-forms.jar
|
||||
jgoodies-looks-2.4.2.jar
|
||||
jh.jar
|
||||
jna-utils.jar
|
||||
jna.jar
|
||||
jsch-0.1.50.jar
|
||||
jsr166e.jar
|
||||
jsr173_1.0_api.jar
|
||||
junit.jar
|
||||
junit-4.10.jar
|
||||
junit.jar
|
||||
log4j.jar
|
||||
jgoodies-common-1.2.1.jar
|
||||
jgoodies-looks-2.4.2.jar
|
||||
markdownj-core-0.4.2-SNAPSHOT.jar
|
||||
microba.jar
|
||||
miglayout-swing.jar
|
||||
nanoxml-2.2.3.jar
|
||||
nekohtml-1.9.14.jar
|
||||
ecj-4.2.1.jar
|
||||
netty-all.jar
|
||||
oromatcher.jar
|
||||
picocontainer.jar
|
||||
protobuf-2.5.0.jar
|
||||
proxy-vole_20120920.jar
|
||||
resolver.jar
|
||||
rhino-js-1_7R4.jar
|
||||
sanselan-0.98-snapshot.jar
|
||||
serviceMessages.jar
|
||||
snappy-java-1.0.5.jar
|
||||
swingx-core-1.6.2.jar
|
||||
trove4j.jar
|
||||
velocity.jar
|
||||
winp-1.17-patched.jar
|
||||
@@ -46,8 +52,3 @@ xerces.jar
|
||||
xmlrpc-2.0.jar
|
||||
xpp3-1.1.4-min.jar
|
||||
xstream-1.4.3.jar
|
||||
swingx-core-1.6.2.jar
|
||||
netty-all.jar
|
||||
protobuf-2.5.0.jar
|
||||
rhino-js-1_7R4.jar
|
||||
proxy-vole_20120920.jar
|
||||
|
||||
Binary file not shown.
+1
-1
@@ -24,7 +24,7 @@ public class DaemonCodeAnalyzerSettings {
|
||||
return ServiceManager.getService(DaemonCodeAnalyzerSettings.class);
|
||||
}
|
||||
|
||||
public boolean NEXT_ERROR_ACTION_GOES_TO_ERRORS_FIRST = false;
|
||||
public boolean NEXT_ERROR_ACTION_GOES_TO_ERRORS_FIRST = true;
|
||||
public int AUTOREPARSE_DELAY = 300;
|
||||
public boolean SHOW_ADD_IMPORT_HINTS = true;
|
||||
@NonNls public String NO_AUTO_IMPORT_PATTERN = "[a-z].?";
|
||||
|
||||
+3
-8
@@ -19,6 +19,7 @@ import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -46,10 +47,7 @@ public class InconsistentLineSeparatorsInspection extends LocalInspectionTool {
|
||||
}
|
||||
|
||||
final Project project = holder.getProject();
|
||||
final String projectLineSeparator = CodeStyleFacade.getInstance(project).getLineSeparator();
|
||||
if (projectLineSeparator == null) {
|
||||
return;
|
||||
}
|
||||
final String projectLineSeparator = FileDocumentManager.getInstance().getLineSeparator(null, project);
|
||||
|
||||
final VirtualFile virtualFile = file.getVirtualFile();
|
||||
if (virtualFile == null || !AbstractConvertLineSeparatorsAction.shouldProcess(virtualFile, project)) {
|
||||
@@ -88,10 +86,7 @@ public class InconsistentLineSeparatorsInspection extends LocalInspectionTool {
|
||||
return;
|
||||
}
|
||||
|
||||
final String lineSeparator = CodeStyleFacade.getInstance(project).getLineSeparator();
|
||||
if (lineSeparator == null) {
|
||||
return;
|
||||
}
|
||||
final String lineSeparator = FileDocumentManager.getInstance().getLineSeparator(null, project);
|
||||
|
||||
final VirtualFile virtualFile = ((PsiFile)psiElement).getVirtualFile();
|
||||
if (virtualFile != null) {
|
||||
@@ -40,13 +40,18 @@ public class Main {
|
||||
|
||||
private static final String AWT_HEADLESS = "java.awt.headless";
|
||||
private static final String PLATFORM_PREFIX_PROPERTY = "idea.platform.prefix";
|
||||
private static final String[] NO_ARGS = {};
|
||||
|
||||
private static boolean isHeadless;
|
||||
private static boolean isCommandLine;
|
||||
|
||||
private Main() { }
|
||||
|
||||
public static void main(final String[] args) {
|
||||
public static void main(String[] args) {
|
||||
if (args.length == 1 && "%f".equals(args[0])) {
|
||||
args = NO_ARGS;
|
||||
}
|
||||
|
||||
setFlags(args);
|
||||
|
||||
if (isHeadless()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -19,10 +19,13 @@
|
||||
*/
|
||||
package com.intellij.concurrency;
|
||||
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public interface Job<T> {
|
||||
// the lower the priority the more important the task is
|
||||
@@ -46,6 +49,7 @@ public interface Job<T> {
|
||||
|
||||
boolean isDone();
|
||||
|
||||
void waitForCompletion(int millis) throws InterruptedException, ExecutionException, TimeoutException;
|
||||
|
||||
@NotNull
|
||||
Job NULL_JOB = new Job() {
|
||||
@@ -54,6 +58,11 @@ public interface Job<T> {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForCompletion(int millis) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
@@ -65,32 +74,32 @@ public interface Job<T> {
|
||||
|
||||
@Override
|
||||
public void addTask(@NotNull Callable task) {
|
||||
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(@NotNull Runnable task, Object result) {
|
||||
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(@NotNull Runnable task) {
|
||||
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List scheduleAndWaitForResults() throws Throwable {
|
||||
return null;
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void schedule() {
|
||||
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.intellij.util.Function;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.DistinctRootsCollection;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import com.intellij.util.text.StringFactory;
|
||||
@@ -550,4 +551,27 @@ public class VfsUtilCore {
|
||||
return VfsUtilCore.isAncestor(ancestor, virtualFile, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void processFilesRecursively(@NotNull VirtualFile root,
|
||||
@NotNull Processor<VirtualFile> processor,
|
||||
@NotNull Convertor<VirtualFile, Boolean> directoryFilter) {
|
||||
if (!processor.process(root)) return;
|
||||
|
||||
if (root.isDirectory() && directoryFilter.convert(root)) {
|
||||
final LinkedList<VirtualFile[]> queue = new LinkedList<VirtualFile[]>();
|
||||
|
||||
queue.add(root.getChildren());
|
||||
|
||||
do {
|
||||
final VirtualFile[] files = queue.removeFirst();
|
||||
|
||||
for (VirtualFile file : files) {
|
||||
if (!processor.process(file)) return;
|
||||
if (file.isDirectory() && directoryFilter.convert(file)) {
|
||||
queue.add(file.getChildren());
|
||||
}
|
||||
}
|
||||
} while (!queue.isEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -29,7 +29,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
public class ProgressWrapper extends AbstractProgressIndicatorBase {
|
||||
private final ProgressIndicator myOriginal;
|
||||
|
||||
private ProgressWrapper(@NotNull ProgressIndicator original) {
|
||||
protected ProgressWrapper(@NotNull ProgressIndicator original) {
|
||||
myOriginal = original;
|
||||
}
|
||||
|
||||
|
||||
+8
-9
@@ -21,12 +21,12 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.FileIndexFacade;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.LineSeparator;
|
||||
import com.intellij.util.Processor;
|
||||
@@ -40,14 +40,13 @@ import java.io.IOException;
|
||||
* @author Nikolai Matveev
|
||||
*/
|
||||
public abstract class AbstractConvertLineSeparatorsAction extends AnAction {
|
||||
|
||||
private static Logger LOG = Logger.getInstance("#com.intellij.codeStyle.AbstractConvertLineSeparatorsAction");
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeStyle.AbstractConvertLineSeparatorsAction");
|
||||
|
||||
@NotNull
|
||||
private final String mySeparator;
|
||||
|
||||
protected AbstractConvertLineSeparatorsAction(@Nullable String text, @NotNull LineSeparator separator) {
|
||||
this(separator.toString() + " - " + text, separator.getSeparatorString());
|
||||
this(separator + " - " + text, separator.getSeparatorString());
|
||||
}
|
||||
|
||||
protected AbstractConvertLineSeparatorsAction(@Nullable String text, @NotNull String separator) {
|
||||
@@ -98,9 +97,9 @@ public abstract class AbstractConvertLineSeparatorsAction extends AnAction {
|
||||
projectVirtualDirectory = null;
|
||||
}
|
||||
|
||||
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
|
||||
final FileTypeRegistry fileTypeManager = FileTypeRegistry.getInstance();
|
||||
for (VirtualFile file : virtualFiles) {
|
||||
VfsUtil.processFilesRecursively(
|
||||
VfsUtilCore.processFilesRecursively(
|
||||
file,
|
||||
new Processor<VirtualFile>() {
|
||||
@Override
|
||||
@@ -115,7 +114,7 @@ public abstract class AbstractConvertLineSeparatorsAction extends AnAction {
|
||||
@Override
|
||||
public Boolean convert(VirtualFile dir) {
|
||||
return !dir.equals(projectVirtualDirectory)
|
||||
&& !fileTypeManager.isFileIgnored(dir.getName()); // Exclude files like '.git'
|
||||
&& !fileTypeManager.isFileIgnored(dir); // Exclude files like '.git'
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -125,7 +124,7 @@ public abstract class AbstractConvertLineSeparatorsAction extends AnAction {
|
||||
public static boolean shouldProcess(@NotNull VirtualFile file, @NotNull Project project) {
|
||||
if (file.isDirectory()
|
||||
|| !file.isWritable()
|
||||
|| FileTypeManager.getInstance().isFileIgnored(file)
|
||||
|| FileTypeRegistry.getInstance().isFileIgnored(file)
|
||||
|| file.getFileType().isBinary()
|
||||
|| file.equals(project.getProjectFile())
|
||||
|| file.equals(project.getWorkspaceFile()))
|
||||
@@ -38,9 +38,9 @@ public abstract class IdFilter {
|
||||
ContentIterator iterator = new ContentIterator() {
|
||||
@Override
|
||||
public boolean processFile(VirtualFile fileOrDir) {
|
||||
idSet.set(
|
||||
((VirtualFileWithId)fileOrDir).getId()
|
||||
);
|
||||
int id = ((VirtualFileWithId)fileOrDir).getId();
|
||||
if (id < 0) id = -id; // workaround for encountering invalid files, see EA-49915, EA-50599
|
||||
idSet.set(id);
|
||||
ProgressManager.checkCanceled();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ public interface FormattingDocumentModel {
|
||||
*/
|
||||
int getTextLength();
|
||||
|
||||
@NotNull
|
||||
Document getDocument();
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -50,7 +50,7 @@ public class CommonCodeStyleSettings {
|
||||
private ArrangementSettings myArrangementSettings;
|
||||
private CodeStyleSettings myRootSettings;
|
||||
private IndentOptions myIndentOptions;
|
||||
private FileType myFileType;
|
||||
private final FileType myFileType;
|
||||
private boolean myForceArrangeMenuAvailable;
|
||||
|
||||
@NonNls private static final String INDENT_OPTIONS_TAG = "indentOptions";
|
||||
@@ -61,10 +61,7 @@ public class CommonCodeStyleSettings {
|
||||
}
|
||||
|
||||
public CommonCodeStyleSettings(Language language) {
|
||||
myLanguage = language;
|
||||
if (language != null) {
|
||||
myFileType = language.getAssociatedFileType();
|
||||
}
|
||||
this(language, language == null ? null : language.getAssociatedFileType());
|
||||
}
|
||||
|
||||
void setRootSettings(@NotNull CodeStyleSettings rootSettings) {
|
||||
|
||||
+24
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -19,7 +19,6 @@ package com.intellij.codeInsight.daemon.impl;
|
||||
import com.intellij.codeHighlighting.HighlightingPass;
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
|
||||
import com.intellij.concurrency.Job;
|
||||
import com.intellij.concurrency.JobImpl;
|
||||
import com.intellij.concurrency.JobLauncher;
|
||||
import com.intellij.injected.editor.EditorWindow;
|
||||
import com.intellij.openapi.Disposable;
|
||||
@@ -47,7 +46,6 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
@@ -79,17 +77,17 @@ public abstract class PassExecutorService implements Disposable {
|
||||
submittedPass.cancel();
|
||||
}
|
||||
if (waitForTermination) {
|
||||
for (Job<Void> job : mySubmittedPasses.values()) {
|
||||
try {
|
||||
if (job instanceof JobImpl) {
|
||||
JobImpl ji = (JobImpl)job;
|
||||
if (!job.isDone()) ji.waitForTermination();
|
||||
}
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
LOG.error(throwable);
|
||||
try {
|
||||
while (!waitFor(50)) {
|
||||
int i = 0;
|
||||
}
|
||||
}
|
||||
catch (ProcessCanceledException ignored) {
|
||||
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
LOG.error(throwable);
|
||||
}
|
||||
}
|
||||
mySubmittedPasses.clear();
|
||||
}
|
||||
@@ -360,7 +358,9 @@ public abstract class PassExecutorService implements Disposable {
|
||||
catch (ProcessCanceledException e) {
|
||||
log(myUpdateProgress, myPass, "Canceled ");
|
||||
|
||||
myUpdateProgress.cancel(e); //in case when some smart asses throw PCE just for fun
|
||||
if (!myUpdateProgress.isCanceled()) {
|
||||
myUpdateProgress.cancel(e); //in case when some smart asses throw PCE just for fun
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
myUpdateProgress.cancel(e);
|
||||
@@ -518,20 +518,23 @@ public abstract class PassExecutorService implements Disposable {
|
||||
return indicator.getUserData(THROWABLE_KEY);
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public void waitFor(int millis) throws Exception {
|
||||
// return true if terminated
|
||||
public boolean waitFor(int millis) throws Throwable {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
try {
|
||||
for (Job<Void> job : mySubmittedPasses.values()) {
|
||||
if (!job.isDone()) {
|
||||
for (FutureTask task : ((JobImpl)job).getTasks()) {
|
||||
task.get(millis, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
job.waitForCompletion(millis);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (TimeoutException ignored) {
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
return true;
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-5
@@ -108,8 +108,9 @@ public class AutoHardWrapHandler {
|
||||
int line = document.getLineNumber(caretOffset);
|
||||
int startOffset = document.getLineStartOffset(line);
|
||||
int endOffset = document.getLineEndOffset(line);
|
||||
final String endOfString = document.getText().substring(caretOffset, endOffset);
|
||||
final boolean endsWithSpaces = StringUtil.isEmptyOrSpaces(endOfString);
|
||||
|
||||
final CharSequence endOfString = document.getCharsSequence().subSequence(caretOffset, endOffset);
|
||||
final boolean endsWithSpaces = StringUtil.isEmptyOrSpaces(String.valueOf(endOfString));
|
||||
// Check if right margin is exceeded.
|
||||
int margin = editor.getSettings().getRightMargin(project);
|
||||
if (margin <= 0) {
|
||||
@@ -185,14 +186,16 @@ public class AutoHardWrapHandler {
|
||||
caretOffsetDiff[0] += event.getNewLength() - event.getOldLength();
|
||||
}
|
||||
|
||||
if (event.getNewLength() <= event.getOldLength() && endsWithSpaces) {
|
||||
// There is a possible case that document fragment is removed because of auto-formatting.
|
||||
// We don't want to process such events in case of current string ends with spaces.
|
||||
if (autoFormatted(event)) {
|
||||
return;
|
||||
}
|
||||
wrapIntroducedSymbolsNumber[0] += event.getNewLength() - event.getOldLength();
|
||||
}
|
||||
|
||||
private boolean autoFormatted(DocumentEvent event) {
|
||||
return event.getNewLength() <= event.getOldLength() && endsWithSpaces;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void documentChanged(DocumentEvent event) {
|
||||
}
|
||||
|
||||
+4
-1
@@ -65,7 +65,10 @@ public class LiveTemplateLookupElement extends LookupElement {
|
||||
}
|
||||
presentation.setTypeText(" [" + KeyEvent.getKeyText(shortcutChar) + "] ");
|
||||
}
|
||||
presentation.setTailText(" (" + myTemplate.getDescription() + ")", true);
|
||||
String description = myTemplate.getDescription();
|
||||
if (description != null) {
|
||||
presentation.setTailText(" (" + description + ")", true);
|
||||
}
|
||||
} else {
|
||||
presentation.setTypeText(myTemplate.getDescription());
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
*/
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.codeStyle.CodeStyleFacade;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.lang.properties.charset.Native2AsciiCharset;
|
||||
@@ -153,7 +152,7 @@ public class LossyEncodingInspection extends LocalInspectionTool {
|
||||
if (separator == null) {
|
||||
separator = documentManager.isDocumentUnsaved(document) ?
|
||||
FileDocumentManagerImpl.getLineSeparator(document, virtualFile) :
|
||||
CodeStyleFacade.getInstance(project).getLineSeparator();
|
||||
FileDocumentManager.getInstance().getLineSeparator(null, project);
|
||||
}
|
||||
String toSave = StringUtil.convertLineSeparators(text, separator);
|
||||
byte[] bom = virtualFile.getBOM();
|
||||
|
||||
+1
@@ -163,6 +163,7 @@ public class CommonContentEntriesEditor extends ModuleElementsEditor {
|
||||
entriesPanel.add(new ToolbarPanel(myScrollPane, group), BorderLayout.CENTER);
|
||||
|
||||
final Splitter splitter = new Splitter(false);
|
||||
splitter.setProportion(0.4f);
|
||||
splitter.setHonorComponentsMinimumSize(true);
|
||||
mainPanel.add(splitter, BorderLayout.CENTER);
|
||||
|
||||
|
||||
@@ -39,14 +39,14 @@ import org.jetbrains.annotations.Nullable;
|
||||
public class DocumentBasedFormattingModel implements FormattingModel {
|
||||
private final Block myRootBlock;
|
||||
private final FormattingDocumentModel myDocumentModel;
|
||||
private final Document myDocument;
|
||||
@NotNull private final Document myDocument;
|
||||
private final Project myProject;
|
||||
private final CodeStyleSettings mySettings;
|
||||
private final FileType myFileType;
|
||||
private final PsiFile myFile;
|
||||
|
||||
public DocumentBasedFormattingModel(final Block rootBlock,
|
||||
final Document document,
|
||||
@NotNull final Document document,
|
||||
final Project project,
|
||||
final CodeStyleSettings settings,
|
||||
final FileType fileType,
|
||||
@@ -221,6 +221,7 @@ public class DocumentBasedFormattingModel implements FormattingModel {
|
||||
return mySettings.getIndentOptions(myFileType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Document getDocument() {
|
||||
return myDocument;
|
||||
}
|
||||
|
||||
@@ -38,13 +38,13 @@ public class FormattingDocumentModelImpl implements FormattingDocumentModel {
|
||||
|
||||
private final WhiteSpaceFormattingStrategy myWhiteSpaceStrategy;
|
||||
//private final CharBuffer myBuffer = CharBuffer.allocate(1);
|
||||
private final Document myDocument;
|
||||
@NotNull private final Document myDocument;
|
||||
private final PsiFile myFile;
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.formatter.FormattingDocumentModelImpl");
|
||||
private final CodeStyleSettings mySettings;
|
||||
|
||||
public FormattingDocumentModelImpl(final Document document, PsiFile file) {
|
||||
public FormattingDocumentModelImpl(@NotNull final Document document, PsiFile file) {
|
||||
myDocument = document;
|
||||
myFile = file;
|
||||
if (file != null) {
|
||||
@@ -117,6 +117,7 @@ public class FormattingDocumentModelImpl implements FormattingDocumentModel {
|
||||
return myDocument.getTextLength();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Document getDocument() {
|
||||
return myDocument;
|
||||
|
||||
@@ -175,6 +175,7 @@ public class CodeFormatterFacade {
|
||||
|
||||
if (builder != null) {
|
||||
if (file.getTextLength() > 0) {
|
||||
LOG.assertTrue(document != null);
|
||||
try {
|
||||
final PsiElement startElement = file.findElementAt(textRanges.get(0).getTextRange().getStartOffset());
|
||||
final PsiElement endElement = file.findElementAt(textRanges.get(textRanges.size() - 1).getTextRange().getEndOffset() - 1);
|
||||
|
||||
@@ -567,28 +567,6 @@ public class VfsUtil extends VfsUtilCore {
|
||||
});
|
||||
}
|
||||
|
||||
public static void processFilesRecursively(@NotNull VirtualFile root, @NotNull Processor<VirtualFile> processor,
|
||||
@NotNull Convertor<VirtualFile, Boolean> directoryFilter) {
|
||||
if (!processor.process(root)) return;
|
||||
|
||||
if (root.isDirectory() && directoryFilter.convert(root)) {
|
||||
final LinkedList<VirtualFile[]> queue = new LinkedList<VirtualFile[]>();
|
||||
|
||||
queue.add(root.getChildren());
|
||||
|
||||
do {
|
||||
final VirtualFile[] files = queue.removeFirst();
|
||||
|
||||
for (VirtualFile file : files) {
|
||||
if (!processor.process(file)) return;
|
||||
if (file.isDirectory() && directoryFilter.convert(file)) {
|
||||
queue.add(file.getChildren());
|
||||
}
|
||||
}
|
||||
} while (!queue.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T> T processInputStream(@NotNull final VirtualFile file, @NotNull Function<InputStream, T> function) {
|
||||
InputStream stream = null;
|
||||
@@ -598,7 +576,8 @@ public class VfsUtil extends VfsUtilCore {
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.concurrency;
|
||||
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.util.Processor;
|
||||
import jsr166e.CountedCompleter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Executes processor on array elements in range from lo (inclusive) to hi (exclusive).
|
||||
* To do this it starts executing processor on first array items and, if it takes too much time, splits the work and forks the right half.
|
||||
* The series of splits lead to linked list of forked sub tasks, each of which is a CountedCompleter of its own,
|
||||
* having this task as its parent.
|
||||
* After the first pass on the array, this task attempts to steal work from the recently forked off sub tasks,
|
||||
* by traversing the linked subtasks list, unforking each subtask and calling execAndForkSubTasks() on each recursively.
|
||||
* After that, the task completes itself.
|
||||
* The process of completing traverses task parent hierarchy, decrementing each pending count until it either
|
||||
* decrements not-zero pending count and stops or
|
||||
* reaches the top, in which case it invokes {@link jsr166e.ForkJoinTask#quietlyComplete()} which causes the top level task to wake up and join successfully.
|
||||
* The exceptions from the sub tasks bubble up to the top and saved in {@link #throwable}.
|
||||
*/
|
||||
public class ApplierCompleter extends CountedCompleter<Void> {
|
||||
private final boolean runInReadAction;
|
||||
private final ProgressIndicator progressIndicator;
|
||||
@NotNull
|
||||
private final List array;
|
||||
@NotNull
|
||||
private final Processor processor;
|
||||
private final int lo;
|
||||
private final int hi;
|
||||
private final ApplierCompleter next; // keeps track of right-hand-side tasks
|
||||
volatile Throwable throwable;
|
||||
|
||||
// if not null, the read action has failed and this list contains unfinished subtasks
|
||||
private List<ApplierCompleter> failedSubTasks;
|
||||
|
||||
//private final List<ApplierCompleter> children = new ArrayList<ApplierCompleter>();
|
||||
|
||||
ApplierCompleter(ApplierCompleter parent,
|
||||
boolean runInReadAction,
|
||||
@NotNull ProgressIndicator progressIndicator,
|
||||
@NotNull List array,
|
||||
@NotNull Processor processor,
|
||||
int lo,
|
||||
int hi,
|
||||
ApplierCompleter next) {
|
||||
super(parent);
|
||||
this.runInReadAction = runInReadAction;
|
||||
this.progressIndicator = progressIndicator;
|
||||
this.array = array;
|
||||
this.processor = processor;
|
||||
this.lo = lo;
|
||||
this.hi = hi;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compute() {
|
||||
compute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
execAndForkSubTasks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void compute(@NotNull final Runnable process) {
|
||||
Runnable toRun = runInReadAction ? new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(process)) {
|
||||
failedSubTasks = new ArrayList<ApplierCompleter>();
|
||||
failedSubTasks.add(ApplierCompleter.this);
|
||||
doComplete(throwable);
|
||||
}
|
||||
}
|
||||
} : process;
|
||||
ProgressIndicator existing = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (existing == progressIndicator) {
|
||||
toRun.run();
|
||||
}
|
||||
else {
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(toRun, progressIndicator);
|
||||
}
|
||||
}
|
||||
|
||||
static class ComputationAbortedException extends RuntimeException {}
|
||||
// executes tasks one by one and forks right halves if it takes too much time
|
||||
// returns the linked list of forked halves - they all need to be joined; null means all tasks have been executed, nothing was forked
|
||||
@Nullable
|
||||
private ApplierCompleter execAndForkSubTasks() {
|
||||
int hi = this.hi;
|
||||
long start = System.currentTimeMillis();
|
||||
ApplierCompleter right = null;
|
||||
Throwable throwable = null;
|
||||
try {
|
||||
for (int i = lo; i < hi; ++i) {
|
||||
progressIndicator.checkCanceled();
|
||||
if (!processor.process(array.get(i))) throw new ComputationAbortedException();
|
||||
long finish = System.currentTimeMillis();
|
||||
long elapsed = finish - start;
|
||||
if (elapsed > 10 && hi - i >= 2 && getSurplusQueuedTaskCount() <= JobSchedulerImpl.CORES_COUNT) {
|
||||
int mid = i + hi >>> 1;
|
||||
right = new ApplierCompleter(this, runInReadAction, progressIndicator, array, processor, mid, hi, right);
|
||||
//children.add(right);
|
||||
addToPendingCount(1);
|
||||
right.fork();
|
||||
hi = mid;
|
||||
start = finish;
|
||||
}
|
||||
}
|
||||
|
||||
// traverse the list looking for a task available for stealing
|
||||
if (right != null) {
|
||||
right.tryToExecAllList();
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
cancelProgress();
|
||||
throwable = e;
|
||||
}
|
||||
finally {
|
||||
doComplete(throwable == null ? this.throwable : throwable);
|
||||
}
|
||||
return right;
|
||||
}
|
||||
|
||||
private void doComplete(Throwable throwable) {
|
||||
ApplierCompleter a = this;
|
||||
ApplierCompleter child = a;
|
||||
while (true) {
|
||||
if (throwable != null) {
|
||||
a.throwable = throwable;
|
||||
}
|
||||
if (a.getPendingCount() == 0) {
|
||||
if (throwable == null) {
|
||||
a.onCompletion(child);
|
||||
}
|
||||
else {
|
||||
a.throwable = throwable;
|
||||
// currently avoid using onExceptionalCompletion since it leaks exceptions via jsr166e.ForkJoinTask.exceptionTable
|
||||
a.onCompletion(child);
|
||||
//a.onExceptionalCompletion(throwable, child);
|
||||
}
|
||||
child = a;
|
||||
a = (ApplierCompleter)a.getCompleter();
|
||||
if (a == null) {
|
||||
if (throwable == null) {
|
||||
child.quietlyComplete();
|
||||
}
|
||||
else {
|
||||
child.throwable = throwable;
|
||||
// currently avoid using completeExceptionally since it leaks exceptions via jsr166e.ForkJoinTask.exceptionTable
|
||||
child.quietlyComplete();
|
||||
//child.completeExceptionally(throwable);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (a.decrementPendingCountUnlessZero() != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelProgress() {
|
||||
if (!progressIndicator.isCanceled()) {
|
||||
progressIndicator.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// tries to unfork, execute and re-link subtasks
|
||||
private void tryToExecAllList() {
|
||||
ApplierCompleter right = this;
|
||||
while (right != null) {
|
||||
if (right.tryUnfork()) {
|
||||
right.execAndForkSubTasks();
|
||||
}
|
||||
right = right.next;
|
||||
}
|
||||
}
|
||||
|
||||
boolean completeTaskWhichFailToAcquireReadAction() {
|
||||
if (failedSubTasks == null) {
|
||||
return true;
|
||||
}
|
||||
final boolean[] result = {true};
|
||||
// these tasks could not be executed in the other thread; do them here
|
||||
for (final ApplierCompleter task : failedSubTasks) {
|
||||
task.failedSubTasks = null;
|
||||
task.compute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = task.lo; i < task.hi; ++i) {
|
||||
if (!task.processor.process(task.array.get(i))) {
|
||||
result[0] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
assert task.failedSubTasks == null;
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return System.identityHashCode(this) + " ("+lo+"-"+hi+")";
|
||||
}
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package com.intellij.concurrency;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class JobImpl<T> implements Job<T> {
|
||||
private static volatile long ourJobsCounter = 0;
|
||||
private final long myJobIndex = ourJobsCounter++;
|
||||
private final int myPriority;
|
||||
private final List<PrioritizedFutureTask<T>> myFutures = new ArrayList<PrioritizedFutureTask<T>>();
|
||||
private volatile boolean canceled = false;
|
||||
private final AtomicInteger runningTasks = new AtomicInteger();
|
||||
private volatile boolean scheduled;
|
||||
private final boolean myFailFastOnAcquireReadAction;
|
||||
|
||||
JobImpl(int priority, boolean failFastOnAcquireReadAction) {
|
||||
myPriority = priority;
|
||||
myFailFastOnAcquireReadAction = failFastOnAcquireReadAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(@NotNull Callable<T> task) {
|
||||
addTask(task, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(@NotNull Runnable task, T result) {
|
||||
addTask(Executors.callable(task, result));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(@NotNull Runnable task) {
|
||||
addTask(Executors.callable(task, (T)null));
|
||||
}
|
||||
|
||||
public void addTask(@NotNull Callable<T> callable, final Consumer<Future> onDoneCallback) {
|
||||
checkNotScheduled();
|
||||
|
||||
PrioritizedFutureTask<T> future =
|
||||
new PrioritizedFutureTask<T>(callable, this, myJobIndex, JobSchedulerImpl.currentTaskIndex(), myPriority, myFailFastOnAcquireReadAction){
|
||||
@Override
|
||||
protected void done() {
|
||||
super.done();
|
||||
if (onDoneCallback != null) {
|
||||
onDoneCallback.consume(this);
|
||||
}
|
||||
//TODO[cdr]: consider clearing thread locals: ReflectionUtil.resetThreadlocals();
|
||||
}
|
||||
};
|
||||
synchronized (myFutures) {
|
||||
myFutures.add(future);
|
||||
}
|
||||
runningTasks.incrementAndGet();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<T> scheduleAndWaitForResults() throws Throwable {
|
||||
checkCanSchedule();
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
boolean callerHasReadAccess = application != null && application.isReadAccessAllowed();
|
||||
scheduleAndWaitForResults(callerHasReadAccess);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void scheduleAndWaitForResults(boolean runInReadAction) throws Throwable {
|
||||
// Don't bother scheduling if we only have one processor or only one task
|
||||
boolean reallySchedule;
|
||||
PrioritizedFutureTask[] tasks = getTasks();
|
||||
synchronized (myFutures) {
|
||||
reallySchedule = JobSchedulerImpl.CORES_COUNT >= 2 && myFutures.size() >= 2;
|
||||
}
|
||||
scheduled = true;
|
||||
|
||||
if (!reallySchedule) {
|
||||
for (PrioritizedFutureTask future : tasks) {
|
||||
future.run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
submitTasks(tasks, runInReadAction, false);
|
||||
|
||||
// in case of imbalanced tasks one huge task can stuck running and we would fall to waitForTermination instead of doing useful work
|
||||
//// http://gafter.blogspot.com/2006/11/thread-pool-puzzler.html
|
||||
//for (PrioritizedFutureTask task : tasks) {
|
||||
// task.run();
|
||||
//}
|
||||
//
|
||||
while (!isDone()) {
|
||||
Runnable task = JobSchedulerImpl.stealTask();
|
||||
if (task == null) break;
|
||||
|
||||
task.run();
|
||||
}
|
||||
|
||||
waitForTermination();
|
||||
}
|
||||
|
||||
public void waitForTermination() throws Throwable {
|
||||
Throwable ex = null;
|
||||
PrioritizedFutureTask[] tasks = getTasks();
|
||||
for (PrioritizedFutureTask f : tasks) {
|
||||
try {
|
||||
// this loop is for workaround of mysterious bug
|
||||
// when sometimes future hangs inside parkAndCheckForInterrupt() during unbounded get()
|
||||
while(true) {
|
||||
try {
|
||||
f.get(10, TimeUnit.MILLISECONDS);
|
||||
break;
|
||||
}
|
||||
catch (TimeoutException e) {
|
||||
if (f.isDone()) {
|
||||
f.get(); // does awaitTermination(), and there is no chance to hang
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (CancellationException ignore) {
|
||||
// already cancelled
|
||||
cancel();
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
cancel();
|
||||
|
||||
Throwable cause = e.getCause();
|
||||
if (cause != null) {
|
||||
ex = cause;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ex != null) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
checkScheduled();
|
||||
if (canceled) return;
|
||||
canceled = true;
|
||||
|
||||
PrioritizedFutureTask[] tasks = getTasks();
|
||||
for (PrioritizedFutureTask future : tasks) {
|
||||
future.cancel(false);
|
||||
}
|
||||
runningTasks.set(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
checkScheduled();
|
||||
return canceled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void schedule() {
|
||||
checkCanSchedule();
|
||||
scheduled = true;
|
||||
|
||||
PrioritizedFutureTask[] tasks = getTasks();
|
||||
|
||||
submitTasks(tasks, false, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PrioritizedFutureTask[] getTasks() {
|
||||
PrioritizedFutureTask[] tasks;
|
||||
synchronized (myFutures) {
|
||||
tasks = myFutures.toArray(new PrioritizedFutureTask[myFutures.size()]);
|
||||
}
|
||||
return tasks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
checkScheduled();
|
||||
|
||||
return runningTasks.get() <= 0;
|
||||
}
|
||||
|
||||
private void checkCanSchedule() {
|
||||
checkNotScheduled();
|
||||
synchronized (myFutures) {
|
||||
if (myFutures.isEmpty()) {
|
||||
throw new IllegalStateException("No tasks added. You can't schedule a job which has no tasks");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNotScheduled() {
|
||||
if (scheduled) {
|
||||
throw new IllegalStateException("Already running. You can't call this method for a job which is already scheduled");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkScheduled() {
|
||||
if (!scheduled) {
|
||||
throw new IllegalStateException("Cannot call this method for not yet started job");
|
||||
}
|
||||
}
|
||||
|
||||
private static void submitTasks(@NotNull PrioritizedFutureTask[] tasks, boolean runInReadAction, boolean reportExceptions) {
|
||||
for (final PrioritizedFutureTask future : tasks) {
|
||||
JobSchedulerImpl.submitTask(future, runInReadAction, reportExceptions);
|
||||
}
|
||||
}
|
||||
|
||||
void taskDone() {
|
||||
runningTasks.decrementAndGet();
|
||||
}
|
||||
}
|
||||
@@ -19,67 +19,90 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.util.ProgressWrapper;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Processor;
|
||||
import jsr166e.ForkJoinPool;
|
||||
import jsr166e.ForkJoinTask;
|
||||
import jsr166e.ForkJoinWorkerThread;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* @author cdr
|
||||
*/
|
||||
public class JobLauncherImpl extends JobLauncher {
|
||||
private static <T> boolean invokeConcurrentlyForAll(@NotNull final List<? extends T> things,
|
||||
boolean runInReadAction,
|
||||
boolean failFastOnAcquireReadAction,
|
||||
@NotNull final Processor<T> thingProcessor,
|
||||
final ProgressWrapper wrapper) throws ProcessCanceledException {
|
||||
final JobImpl<String> job = new JobImpl<String>(Job.DEFAULT_PRIORITY, failFastOnAcquireReadAction);
|
||||
|
||||
final int chunkSize = Math.max(1, things.size() / Math.max(1, JobSchedulerImpl.CORES_COUNT / 2));
|
||||
for (int i = 0; i < things.size(); i += chunkSize) {
|
||||
// this job chunk is i..i+chunkSize-1
|
||||
final int finalI = i;
|
||||
job.addTask(new Runnable() {
|
||||
private static final AtomicLong bits = new AtomicLong();
|
||||
private static final ForkJoinPool.ForkJoinWorkerThreadFactory FACTORY = new ForkJoinPool.ForkJoinWorkerThreadFactory() {
|
||||
@Override
|
||||
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
|
||||
final int n = addThread();
|
||||
ForkJoinWorkerThread thread = new ForkJoinWorkerThread(pool) {
|
||||
@Override
|
||||
public void run() {
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (int k = finalI; k < finalI + chunkSize && k < things.size(); k++) {
|
||||
T thing = things.get(k);
|
||||
if (!thingProcessor.process(thing)) {
|
||||
job.cancel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
job.cancel();
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
}, wrapper);
|
||||
protected void onTermination(Throwable exception) {
|
||||
finishThread(n);
|
||||
super.onTermination(exception);
|
||||
}
|
||||
});
|
||||
};
|
||||
thread.setName("JobScheduler FJ pool "+ n +"/"+ JobSchedulerImpl.CORES_COUNT);
|
||||
return thread;
|
||||
}
|
||||
|
||||
private int addThread() {
|
||||
boolean set;
|
||||
int n;
|
||||
do {
|
||||
long l = bits.longValue();
|
||||
long next = (l + 1) | l;
|
||||
n = Long.numberOfTrailingZeros(l + 1);
|
||||
set = bits.compareAndSet(l, next);
|
||||
} while (!set);
|
||||
return n;
|
||||
}
|
||||
private void finishThread(int n) {
|
||||
boolean set;
|
||||
do {
|
||||
long l = bits.get();
|
||||
long next = l & ~(1L << n);
|
||||
set = bits.compareAndSet(l, next);
|
||||
} while (!set);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ForkJoinPool pool = new ForkJoinPool(JobSchedulerImpl.CORES_COUNT, FACTORY, null, false);
|
||||
|
||||
private static <T> boolean invokeConcurrentlyForAll(@NotNull final List<T> things,
|
||||
boolean runInReadAction,
|
||||
@NotNull final Processor<? super T> thingProcessor,
|
||||
@NotNull ProgressIndicator wrapper) throws ProcessCanceledException {
|
||||
ApplierCompleter applier = new ApplierCompleter(null, runInReadAction, wrapper, things, thingProcessor, 0, things.size(), null);
|
||||
try {
|
||||
job.scheduleAndWaitForResults(runInReadAction);
|
||||
pool.invoke(applier);
|
||||
if (applier.throwable != null) throw applier.throwable;
|
||||
}
|
||||
catch (ApplierCompleter.ComputationAbortedException e) {
|
||||
return false;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
job.cancel();
|
||||
assert wrapper.isCanceled();
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
job.cancel();
|
||||
throw new ProcessCanceledException(throwable);
|
||||
catch (Error e) {
|
||||
assert wrapper.isCanceled();
|
||||
throw e;
|
||||
}
|
||||
return !job.isCanceled();
|
||||
catch (Throwable e) {
|
||||
assert wrapper.isCanceled();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
assert applier.isDone();
|
||||
return applier.completeTaskWhichFailToAcquireReadAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,22 +115,34 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean invokeConcurrentlyUnderProgress(@NotNull List<? extends T> things,
|
||||
public <T> boolean invokeConcurrentlyUnderProgress(@NotNull final List<? extends T> things,
|
||||
ProgressIndicator progress,
|
||||
boolean runInReadAction,
|
||||
boolean failFastOnAcquireReadAction,
|
||||
@NotNull Processor<T> thingProcessor) {
|
||||
if (things.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (things.size() == 1) {
|
||||
T t = things.get(0);
|
||||
return thingProcessor.process(t);
|
||||
@NotNull final Processor<T> thingProcessor) throws ProcessCanceledException {
|
||||
if (things.isEmpty()) return true;
|
||||
// supply our own indicator even if we haven't given one - to support cancellation
|
||||
final ProgressIndicator wrapper = progress == null ? new ProgressIndicatorBase() : new SensitiveProgressWrapper(progress);
|
||||
|
||||
if (things.size() <= 1 || JobSchedulerImpl.CORES_COUNT <= 2) {
|
||||
final AtomicBoolean result = new AtomicBoolean(true);
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < things.size(); i++) {
|
||||
T thing = things.get(i);
|
||||
if (!thingProcessor.process(thing)) {
|
||||
result.set(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, wrapper);
|
||||
return result.get();
|
||||
}
|
||||
|
||||
// can be already wrapped
|
||||
final ProgressWrapper wrapper = progress instanceof ProgressWrapper ? (ProgressWrapper)progress : ProgressWrapper.wrap(progress);
|
||||
return invokeConcurrentlyForAll(things, runInReadAction, failFastOnAcquireReadAction, thingProcessor, wrapper);
|
||||
return invokeConcurrentlyForAll(things, runInReadAction, thingProcessor, wrapper);
|
||||
}
|
||||
|
||||
// This implementation is not really async
|
||||
@@ -130,22 +165,92 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Job<Void> submitToJobThread(int priority, @NotNull final Runnable action, Consumer<Future> onDoneCallback) {
|
||||
final JobImpl<Void> job = new JobImpl<Void>(priority, false);
|
||||
Callable<Void> callable = new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
try {
|
||||
action.run();
|
||||
}
|
||||
catch (ProcessCanceledException ignored) {
|
||||
// since it's the only task in the job, nothing to cancel
|
||||
}
|
||||
return null;
|
||||
public Job<Void> submitToJobThread(int priority, @NotNull final Runnable action, final Consumer<Future> onDoneCallback) {
|
||||
VoidForkJoinTask task = new VoidForkJoinTask(action, onDoneCallback);
|
||||
pool.submit(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
private static class VoidForkJoinTask extends ForkJoinTask<Void> implements Job<Void> {
|
||||
private final Runnable myAction;
|
||||
private final Consumer<Future> myOnDoneCallback;
|
||||
|
||||
public VoidForkJoinTask(@NotNull Runnable action, @Nullable Consumer<Future> onDoneCallback) {
|
||||
myAction = action;
|
||||
myOnDoneCallback = onDoneCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void getRawResult() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setRawResult(Void value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean exec() {
|
||||
try {
|
||||
myAction.run();
|
||||
complete(null); // complete manually before calling callback
|
||||
}
|
||||
};
|
||||
job.addTask(callable, onDoneCallback);
|
||||
job.schedule();
|
||||
return job;
|
||||
catch (Throwable throwable) {
|
||||
completeExceptionally(throwable);
|
||||
}
|
||||
finally {
|
||||
if (myOnDoneCallback != null) {
|
||||
myOnDoneCallback.consume(this);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////// Job
|
||||
@Override
|
||||
public String getTitle() {
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
return isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(@NotNull Callable<Void> task) {
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(@NotNull Runnable task, Void result) {
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(@NotNull Runnable task) {
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Void> scheduleAndWaitForResults() throws Throwable {
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
cancel(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void schedule() {
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForCompletion(int millis) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
get(millis, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -19,66 +19,6 @@
|
||||
*/
|
||||
package com.intellij.concurrency;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@NonNls
|
||||
public class JobSchedulerImpl extends JobScheduler implements Disposable {
|
||||
public static final int CORES_COUNT = /*1;//*/ Runtime.getRuntime().availableProcessors();
|
||||
|
||||
private static final ThreadFactory WORKERS_FACTORY = new ThreadFactory() {
|
||||
private int threadSeq;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public synchronized Thread newThread(@NotNull final Runnable r) {
|
||||
@NonNls String name = "JobScheduler pool " + threadSeq + "/" + CORES_COUNT;
|
||||
final Thread thread = new Thread(r, name);
|
||||
thread.setPriority(Thread.NORM_PRIORITY);
|
||||
threadSeq++;
|
||||
return thread;
|
||||
}
|
||||
};
|
||||
|
||||
private static final PriorityBlockingQueue<Runnable> ourQueue = new PriorityBlockingQueue<Runnable>();
|
||||
private static final MyExecutor ourExecutor = new MyExecutor();
|
||||
|
||||
static int currentTaskIndex() {
|
||||
return ourQueue.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
((ThreadPoolExecutor)getScheduler()).getQueue().clear();
|
||||
}
|
||||
|
||||
static Runnable stealTask() {
|
||||
return ourQueue.poll();
|
||||
}
|
||||
|
||||
static void submitTask(@NotNull PrioritizedFutureTask future, boolean runInReadAction, boolean reportExceptions) {
|
||||
future.beforeRun(runInReadAction, reportExceptions);
|
||||
ourExecutor.executeTask(future);
|
||||
}
|
||||
|
||||
private static class MyExecutor extends ThreadPoolExecutor {
|
||||
private MyExecutor() {
|
||||
super(CORES_COUNT, Integer.MAX_VALUE, 60 * 10, TimeUnit.SECONDS, ourQueue, WORKERS_FACTORY);
|
||||
}
|
||||
|
||||
private void executeTask(@NotNull PrioritizedFutureTask task) {
|
||||
super.execute(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull Runnable command) {
|
||||
throw new IllegalStateException("Use executeTask() to submit PrioritizedFutureTasks only");
|
||||
}
|
||||
}
|
||||
public abstract class JobSchedulerImpl {
|
||||
public static final int CORES_COUNT = Runtime.getRuntime().availableProcessors();
|
||||
}
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package com.intellij.concurrency;
|
||||
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.application.impl.ApplicationImpl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
class PrioritizedFutureTask<T> extends FutureTask<T> implements Comparable<PrioritizedFutureTask> {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.concurrency.PrioritizedFutureTask");
|
||||
private final JobImpl<T> myJob;
|
||||
private final long myJobIndex;
|
||||
private final int myTaskIndex;
|
||||
private final int myPriority;
|
||||
private final boolean myFailFastOnAcquireReadAction;
|
||||
private volatile boolean myRunInReadAction;
|
||||
private volatile boolean myReportExceptions;
|
||||
|
||||
PrioritizedFutureTask(final Callable<T> callable,
|
||||
JobImpl<T> job,
|
||||
long jobIndex,
|
||||
int taskIndex,
|
||||
int priority,
|
||||
boolean failFastOnAcquireReadAction) {
|
||||
super(callable);
|
||||
myJob = job;
|
||||
myJobIndex = jobIndex;
|
||||
myTaskIndex = taskIndex;
|
||||
myPriority = priority;
|
||||
myFailFastOnAcquireReadAction = failFastOnAcquireReadAction;
|
||||
}
|
||||
|
||||
public void beforeRun(boolean runInReadAction, boolean reportExceptions) {
|
||||
myRunInReadAction = runInReadAction;
|
||||
myReportExceptions = reportExceptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (myJob.isCanceled()) {
|
||||
//set(null);
|
||||
cancel(false); //todo cancel or set?
|
||||
}
|
||||
else {
|
||||
PrioritizedFutureTask.super.run();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (myReportExceptions) {
|
||||
// let exceptions during execution manifest themselves
|
||||
PrioritizedFutureTask.super.get();
|
||||
}
|
||||
}
|
||||
catch (CancellationException ignored) {
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
finally {
|
||||
myJob.taskDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (myRunInReadAction) {
|
||||
// have to start "real" read action so that we cannot start write action until we are finished here
|
||||
if (myFailFastOnAcquireReadAction) {
|
||||
if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(runnable)) {
|
||||
myJob.cancel();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// cannot run readaction here because of possible deadlock when writeaction in the queue
|
||||
boolean old = ApplicationImpl.setExceptionalThreadWithReadAccessFlag(true);
|
||||
try {
|
||||
runnable.run();
|
||||
}
|
||||
finally {
|
||||
ApplicationImpl.setExceptionalThreadWithReadAccessFlag(old);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull final PrioritizedFutureTask o) {
|
||||
int priorityDelta = myPriority - o.myPriority;
|
||||
if (priorityDelta != 0) return priorityDelta;
|
||||
if (myJobIndex != o.myJobIndex) return myJobIndex < o.myJobIndex ? -1 : 1;
|
||||
return myTaskIndex - o.myTaskIndex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.concurrency;
|
||||
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Progress indicator wrapper which reacts to its own cancellation in addition to the cancellation of its wrappee.
|
||||
*/
|
||||
public class SensitiveProgressWrapper extends ProgressWrapper {
|
||||
public SensitiveProgressWrapper(@NotNull ProgressIndicator indicator) {
|
||||
super(indicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
return super.isCanceled() || getOriginalProgressIndicator().isCanceled();
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import com.intellij.openapi.actionSystem.DataProvider;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -643,7 +642,9 @@ public class EditorWindow {
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myTabbedPane.setSelectedIndex(index, focusEditor);
|
||||
if (myTabbedPane != null) {
|
||||
myTabbedPane.setSelectedIndex(index, focusEditor);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -377,13 +377,13 @@ public class FileWatcher {
|
||||
if (fastPath && !changedPaths.isEmpty()) break;
|
||||
|
||||
for (String root : flatWatchRoots) {
|
||||
if (FileUtil.pathsEqual(path, root)) {
|
||||
if (FileUtil.namesEqual(path, root)) {
|
||||
changedPaths.add(path);
|
||||
continue ext;
|
||||
}
|
||||
if (isExact) {
|
||||
String parentPath = new File(path).getParent();
|
||||
if (parentPath != null && FileUtil.pathsEqual(parentPath, root)) {
|
||||
if (parentPath != null && FileUtil.namesEqual(parentPath, root)) {
|
||||
changedPaths.add(path);
|
||||
continue ext;
|
||||
}
|
||||
@@ -397,7 +397,7 @@ public class FileWatcher {
|
||||
}
|
||||
if (!isExact) {
|
||||
String parentPath = new File(root).getParent();
|
||||
if (parentPath != null && FileUtil.pathsEqual(path, parentPath)) {
|
||||
if (parentPath != null && FileUtil.namesEqual(path, parentPath)) {
|
||||
changedPaths.add(root);
|
||||
continue ext;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ ide.appIcon.progress=true
|
||||
ide.appIcon.badge=true
|
||||
ide.appIcon.requestAttention=true
|
||||
|
||||
ide.windowSystem.hScrollChars=15
|
||||
ide.windowSystem.hScrollChars=5
|
||||
ide.windowSystem.vScrollChars=5
|
||||
ide.windowSystem.focusAppOnStartup=true
|
||||
ide.windowSystem.autoShowProcessPopup=false
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -19,6 +19,7 @@ public interface Convertor<Src, Dst> {
|
||||
IntoSelf SELF = new IntoSelf();
|
||||
|
||||
class IntoSelf<Src> implements Convertor<Src, Src> {
|
||||
@Override
|
||||
public Src convert(Src o) {
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<orderEntry type="library" name="Guava" level="project" />
|
||||
<orderEntry type="library" name="CGLIB" level="project" />
|
||||
<orderEntry type="library" name="asm" level="project" />
|
||||
<orderEntry type="library" exported="" name="ForkJoin" level="project" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.booleanIsAlwaysInverted;
|
||||
|
||||
import com.intellij.analysis.AnalysisScope;
|
||||
import com.intellij.codeInsight.daemon.GroupNames;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.reference.*;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class BooleanMethodIsAlwaysInvertedInspectionBase extends GlobalJavaBatchInspectionTool {
|
||||
private static final Key<Boolean> ALWAYS_INVERTED = Key.create("ALWAYS_INVERTED_METHOD");
|
||||
|
||||
private static boolean hasNonInvertedCalls(final RefMethod refMethod) {
|
||||
final Boolean alwaysInverted = refMethod.getUserData(ALWAYS_INVERTED);
|
||||
if (alwaysInverted == null) return true;
|
||||
if (refMethod.isExternalOverride()) return true;
|
||||
if (refMethod.isReferenced() && !alwaysInverted.booleanValue()) return true;
|
||||
final Collection<RefMethod> superMethods = refMethod.getSuperMethods();
|
||||
for (RefMethod superMethod : superMethods) {
|
||||
if (hasNonInvertedCalls(superMethod)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void traverseSuperMethods(RefMethod refMethod,
|
||||
GlobalJavaInspectionContext globalContext,
|
||||
GlobalJavaInspectionContext.UsagesProcessor processor) {
|
||||
final Collection<RefMethod> superMethods = refMethod.getSuperMethods();
|
||||
for (RefMethod superMethod : superMethods) {
|
||||
traverseSuperMethods(superMethod, globalContext, processor);
|
||||
}
|
||||
globalContext.enqueueMethodUsagesProcessor(refMethod, processor);
|
||||
}
|
||||
|
||||
private static void checkMethodCall(RefElement refWhat, final PsiElement element) {
|
||||
if (!(refWhat instanceof RefMethod)) return;
|
||||
final RefMethod refMethod = (RefMethod)refWhat;
|
||||
final PsiElement psiElement = refMethod.getElement();
|
||||
if (!(psiElement instanceof PsiMethod)) return;
|
||||
final PsiMethod psiMethod = (PsiMethod)psiElement;
|
||||
if (!PsiType.BOOLEAN.equals(psiMethod.getReturnType())) return;
|
||||
element.accept(new JavaRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression call) {
|
||||
super.visitMethodCallExpression(call);
|
||||
final PsiReferenceExpression methodExpression = call.getMethodExpression();
|
||||
if (methodExpression.isReferenceTo(psiMethod)) {
|
||||
if (isInvertedMethodCall(methodExpression)) return;
|
||||
refMethod.putUserData(ALWAYS_INVERTED, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isInvertedMethodCall(final PsiReferenceExpression methodExpression) {
|
||||
final PsiPrefixExpression prefixExpression = PsiTreeUtil.getParentOfType(methodExpression, PsiPrefixExpression.class);
|
||||
if (methodExpression.getQualifierExpression() instanceof PsiSuperExpression) return true; //don't flag super calls
|
||||
if (prefixExpression != null) {
|
||||
final IElementType tokenType = prefixExpression.getOperationTokenType();
|
||||
if (tokenType.equals(JavaTokenType.EXCL)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionsBundle.message("boolean.method.is.always.inverted.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getGroupDisplayName() {
|
||||
return GroupNames.DATA_FLOW_ISSUES;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
@NonNls
|
||||
public String getShortName() {
|
||||
return "BooleanMethodIsAlwaysInverted";
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public RefGraphAnnotator getAnnotator(@NotNull final RefManager refManager) {
|
||||
return new BooleanInvertedAnnotator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonProblemDescriptor[] checkElement(@NotNull RefEntity refEntity,
|
||||
@NotNull AnalysisScope scope,
|
||||
@NotNull final InspectionManager manager,
|
||||
@NotNull final GlobalInspectionContext globalContext) {
|
||||
if (refEntity instanceof RefMethod) {
|
||||
RefMethod refMethod = (RefMethod)refEntity;
|
||||
if (!refMethod.isReferenced()) return null;
|
||||
if (hasNonInvertedCalls(refMethod)) return null;
|
||||
if (!refMethod.getSuperMethods().isEmpty()) return null;
|
||||
final PsiMethod psiMethod = (PsiMethod)refMethod.getElement();
|
||||
final PsiIdentifier psiIdentifier = psiMethod.getNameIdentifier();
|
||||
if (psiIdentifier != null) {
|
||||
return new ProblemDescriptor[]{manager.createProblemDescriptor(psiIdentifier,
|
||||
InspectionsBundle
|
||||
.message("boolean.method.is.always.inverted.problem.descriptor"),
|
||||
(LocalQuickFix)getQuickFix(null),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager,
|
||||
@NotNull final GlobalJavaInspectionContext context,
|
||||
@NotNull final ProblemDescriptionsProcessor descriptionsProcessor) {
|
||||
manager.iterate(new RefJavaVisitor() {
|
||||
@Override
|
||||
public void visitMethod(@NotNull final RefMethod refMethod) {
|
||||
if (descriptionsProcessor.getDescriptions(refMethod) != null) { //suspicious method -> need to check external usages
|
||||
final GlobalJavaInspectionContext.UsagesProcessor usagesProcessor = new GlobalJavaInspectionContext.UsagesProcessor() {
|
||||
@Override
|
||||
public boolean process(PsiReference psiReference) {
|
||||
final PsiElement psiReferenceExpression = psiReference.getElement();
|
||||
if (psiReferenceExpression instanceof PsiReferenceExpression &&
|
||||
!isInvertedMethodCall((PsiReferenceExpression)psiReferenceExpression)) {
|
||||
descriptionsProcessor.ignoreElement(refMethod);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
traverseSuperMethods(refMethod, context, usagesProcessor);
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class BooleanInvertedAnnotator extends RefGraphAnnotator {
|
||||
@Override
|
||||
public void onInitialize(RefElement refElement) {
|
||||
if (refElement instanceof RefMethod) {
|
||||
final PsiElement element = refElement.getElement();
|
||||
if (!(element instanceof PsiMethod)) return;
|
||||
if (((PsiMethod)element).getReturnType() != PsiType.BOOLEAN) return;
|
||||
refElement.putUserData(ALWAYS_INVERTED, Boolean.TRUE); //initial mark boolean methods
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMarkReferenced(RefElement refWhat, RefElement refFrom, boolean referencedFromClassInitializer) {
|
||||
checkMethodCall(refWhat, refFrom.getElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.bugs;
|
||||
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiParameterList;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MisspelledCompareToInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"misspelled.compareto.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"misspelled.compareto.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new MisspelledCompareToVisitor();
|
||||
}
|
||||
|
||||
private static class MisspelledCompareToVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NotNull PsiMethod method) {
|
||||
//note: no call to super
|
||||
@NonNls final String methodName = method.getName();
|
||||
if (!"compareto".equals(methodName)) {
|
||||
return;
|
||||
}
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
if (parameterList.getParametersCount() != 1) {
|
||||
return;
|
||||
}
|
||||
registerMethodError(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.bugs;
|
||||
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiParameterList;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MisspelledEqualsInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"misspelled.equals.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"misspelled.equals.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new MisspelledEqualsVisitor();
|
||||
}
|
||||
|
||||
private static class MisspelledEqualsVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NotNull PsiMethod method) {
|
||||
//note: no call to super
|
||||
@NonNls final String methodName = method.getName();
|
||||
if (!"equal".equals(methodName)) {
|
||||
return;
|
||||
}
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
if (parameterList.getParametersCount() != 1) {
|
||||
return;
|
||||
}
|
||||
registerMethodError(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.bugs;
|
||||
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiParameterList;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MisspelledHashcodeInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"misspelled.hashcode.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"misspelled.hashcode.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new MisspelledHashcodeVisitor();
|
||||
}
|
||||
|
||||
private static class MisspelledHashcodeVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NotNull PsiMethod method) {
|
||||
//note: no call to super
|
||||
@NonNls final String methodName = method.getName();
|
||||
if (!"hashcode".equals(methodName)) {
|
||||
return;
|
||||
}
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
if (parameterList.getParametersCount() != 0) {
|
||||
return;
|
||||
}
|
||||
registerMethodError(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.bugs;
|
||||
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiParameterList;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MisspelledToStringInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"misspelled.tostring.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"misspelled.tostring.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new MisspelledToStringVisitor();
|
||||
}
|
||||
|
||||
private static class MisspelledToStringVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NotNull PsiMethod method) {
|
||||
//note: no call to super
|
||||
@NonNls final String methodName = method.getName();
|
||||
if (!"tostring".equals(methodName)) {
|
||||
return;
|
||||
}
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
if (parameterList.getParametersCount() != 0) {
|
||||
return;
|
||||
}
|
||||
registerMethodError(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiAnonymousClass;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiEnumConstantInitializer;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AnonymousInnerClassInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"anonymous.inner.class.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"anonymous.inner.class.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new AnonymousInnerClassVisitor();
|
||||
}
|
||||
|
||||
private static class AnonymousInnerClassVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
//no call to super here, to avoid double counting
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnonymousClass(@NotNull PsiAnonymousClass aClass) {
|
||||
super.visitAnonymousClass(aClass);
|
||||
if (aClass instanceof PsiEnumConstantInitializer) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.util.FileTypeUtils;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.ClassUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ClassInTopLevelPackageInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return "ClassWithoutPackageStatement";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"class.in.top.level.package.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"class.in.top.level.package.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new ClassInTopLevelPackageVisitor();
|
||||
}
|
||||
|
||||
private static class ClassInTopLevelPackageVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
// no call to super, so that it doesn't drill down to inner classes
|
||||
if (FileTypeUtils.isInServerPageFile(aClass)) {
|
||||
return;
|
||||
}
|
||||
if (ClassUtils.isInnerClass(aClass)) {
|
||||
return;
|
||||
}
|
||||
final PsiFile file = aClass.getContainingFile();
|
||||
if (!(file instanceof PsiJavaFile)) {
|
||||
return;
|
||||
}
|
||||
if (((PsiJavaFile)file).getPackageStatement() != null) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.util.FileTypeUtils;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ClassNameDiffersFromFileNameInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"class.name.differs.from.file.name.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"class.name.differs.from.file.name.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new ClassNameDiffersFromFileNameVisitor();
|
||||
}
|
||||
|
||||
private static class ClassNameDiffersFromFileNameVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
// no call to super, so that it doesn't drill down to inner classes
|
||||
if (FileTypeUtils.isInServerPageFile(aClass)) {
|
||||
return;
|
||||
}
|
||||
final PsiElement parent = aClass.getParent();
|
||||
if (!(parent instanceof PsiJavaFile)) {
|
||||
return;
|
||||
}
|
||||
final PsiJavaFile file = (PsiJavaFile)parent;
|
||||
final String className = aClass.getName();
|
||||
if (className == null) {
|
||||
return;
|
||||
}
|
||||
final String fileName = file.getName();
|
||||
final int prefixIndex = fileName.indexOf((int)'.');
|
||||
if (prefixIndex < 0) {
|
||||
return;
|
||||
}
|
||||
final String filenameWithoutPrefix =
|
||||
fileName.substring(0, prefixIndex);
|
||||
if (className.equals(filenameWithoutPrefix)) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.FileTypeUtils;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.fixes.AddToIgnoreIfAnnotatedByListQuickFix;
|
||||
import com.siyeh.ig.ui.ExternalizableStringSet;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class EmptyClassInspectionBase extends BaseInspection {
|
||||
@SuppressWarnings({"PublicField"})
|
||||
public final ExternalizableStringSet ignorableAnnotations = new ExternalizableStringSet();
|
||||
@SuppressWarnings({"PublicField"})
|
||||
public boolean ignoreClassWithParameterization = false;
|
||||
@SuppressWarnings({"PublicField"})
|
||||
public boolean ignoreThrowables = true;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("empty.class.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
final Object element = infos[0];
|
||||
if (element instanceof PsiAnonymousClass) {
|
||||
return InspectionGadgetsBundle.message("empty.anonymous.class.problem.descriptor");
|
||||
}
|
||||
else if (element instanceof PsiClass) {
|
||||
return InspectionGadgetsBundle.message("empty.class.problem.descriptor");
|
||||
}
|
||||
else {
|
||||
return InspectionGadgetsBundle.message("empty.class.file.without.class.problem.descriptor");
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected InspectionGadgetsFix[] buildFixes(Object... infos) {
|
||||
final Object info = infos[0];
|
||||
if (!(info instanceof PsiModifierListOwner)) {
|
||||
return InspectionGadgetsFix.EMPTY_ARRAY;
|
||||
}
|
||||
return AddToIgnoreIfAnnotatedByListQuickFix.build((PsiModifierListOwner)info, ignorableAnnotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new EmptyClassVisitor();
|
||||
}
|
||||
|
||||
private class EmptyClassVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitFile(PsiFile file) {
|
||||
if (!(file instanceof PsiJavaFile)) {
|
||||
return;
|
||||
}
|
||||
final PsiJavaFile javaFile = (PsiJavaFile)file;
|
||||
if (javaFile.getClasses().length != 0) {
|
||||
return;
|
||||
}
|
||||
@NonNls final String fileName = javaFile.getName();
|
||||
if ("package-info.java".equals(fileName)) {
|
||||
return;
|
||||
}
|
||||
registerError(file, file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
//don't call super, to prevent drilldown
|
||||
if (FileTypeUtils.isInServerPageFile(aClass.getContainingFile())) {
|
||||
return;
|
||||
}
|
||||
if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType()) {
|
||||
return;
|
||||
}
|
||||
if (aClass instanceof PsiTypeParameter) {
|
||||
return;
|
||||
}
|
||||
final PsiMethod[] constructors = aClass.getConstructors();
|
||||
if (constructors.length > 0) {
|
||||
return;
|
||||
}
|
||||
final PsiMethod[] methods = aClass.getMethods();
|
||||
if (methods.length > 0) {
|
||||
return;
|
||||
}
|
||||
final PsiField[] fields = aClass.getFields();
|
||||
if (fields.length > 0) {
|
||||
return;
|
||||
}
|
||||
final PsiClassInitializer[] initializers = aClass.getInitializers();
|
||||
if (initializers.length > 0) {
|
||||
return;
|
||||
}
|
||||
if (ignoreClassWithParameterization && isSuperParametrization(aClass)) {
|
||||
return;
|
||||
}
|
||||
if (AnnotationUtil.isAnnotated(aClass, ignorableAnnotations)) {
|
||||
return;
|
||||
}
|
||||
if (ignoreThrowables && InheritanceUtil.isInheritor(aClass, "java.lang.Throwable")) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass, aClass);
|
||||
}
|
||||
|
||||
private boolean hasTypeArguments(PsiReferenceList extendsList) {
|
||||
if (extendsList == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements();
|
||||
for (PsiJavaCodeReferenceElement referenceElement : referenceElements) {
|
||||
final PsiReferenceParameterList parameterList = referenceElement.getParameterList();
|
||||
if (parameterList == null) {
|
||||
continue;
|
||||
}
|
||||
final PsiType[] typeArguments = parameterList.getTypeArguments();
|
||||
if (typeArguments.length != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isSuperParametrization(PsiClass aClass) {
|
||||
if (!(aClass instanceof PsiAnonymousClass)) {
|
||||
final PsiReferenceList extendsList = aClass.getExtendsList();
|
||||
final PsiReferenceList implementsList = aClass.getImplementsList();
|
||||
return hasTypeArguments(extendsList) || hasTypeArguments(implementsList);
|
||||
}
|
||||
final PsiAnonymousClass anonymousClass = (PsiAnonymousClass)aClass;
|
||||
final PsiJavaCodeReferenceElement reference = anonymousClass.getBaseClassReference();
|
||||
final PsiReferenceParameterList parameterList = reference.getParameterList();
|
||||
if (parameterList == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiTypeElement[] elements = parameterList.getTypeParameterElements();
|
||||
for (PsiTypeElement element : elements) {
|
||||
if (element != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiAnonymousClass;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiTypeParameter;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class InnerClassOnInterfaceInspectionBase extends BaseInspection {
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
public boolean m_ignoreInnerInterfaces = false;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return "InnerClassOfInterface";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"inner.class.on.interface.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
final PsiClass parentInterface = (PsiClass)infos[0];
|
||||
final String interfaceName = parentInterface.getName();
|
||||
return InspectionGadgetsBundle.message(
|
||||
"inner.class.on.interface.problem.descriptor", interfaceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new InnerClassOnInterfaceVisitor();
|
||||
}
|
||||
|
||||
private class InnerClassOnInterfaceVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
// no call to super, so that it doesn't drill down to inner classes
|
||||
if (!aClass.isInterface() || aClass.isAnnotationType()) {
|
||||
return;
|
||||
}
|
||||
final PsiClass[] innerClasses = aClass.getInnerClasses();
|
||||
for (final PsiClass innerClass : innerClasses) {
|
||||
if (isInnerClass(innerClass)) {
|
||||
registerClassError(innerClass, aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInnerClass(PsiClass innerClass) {
|
||||
if (innerClass.isEnum()) {
|
||||
return false;
|
||||
}
|
||||
if (innerClass.isAnnotationType()) {
|
||||
return false;
|
||||
}
|
||||
if (innerClass instanceof PsiTypeParameter ||
|
||||
innerClass instanceof PsiAnonymousClass) {
|
||||
return false;
|
||||
}
|
||||
return !(innerClass.isInterface() && m_ignoreInnerInterfaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiDeclarationStatement;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LimitedScopeInnerClassInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"limited.scope.inner.class.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"limited.scope.inner.class.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new LimitedScopeInnerClassVisitor();
|
||||
}
|
||||
|
||||
private static class LimitedScopeInnerClassVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
if (aClass.getParent() instanceof PsiDeclarationStatement) {
|
||||
registerClassError(aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MultipleTopLevelClassesInFileInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"multiple.top.level.classes.in.file.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"multiple.top.level.classes.in.file.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new MultipleTopLevelClassesInFileVisitor();
|
||||
}
|
||||
|
||||
private static class MultipleTopLevelClassesInFileVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
// no call to super, so that it doesn't drill down to inner classes
|
||||
if (!(aClass.getParent() instanceof PsiJavaFile)) {
|
||||
return;
|
||||
}
|
||||
final PsiJavaFile file = (PsiJavaFile)aClass.getParent();
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
int numClasses = 0;
|
||||
final PsiElement[] children = file.getChildren();
|
||||
for (final PsiElement child : children) {
|
||||
if (child instanceof PsiClass) {
|
||||
numClasses++;
|
||||
}
|
||||
}
|
||||
if (numClasses <= 1) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.UtilityClassUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class NonFinalUtilityClassInspectionBase extends BaseInspection {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("non.final.utility.class.display.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("non.final.utility.class.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new NonFinalUtilityClassVisitor();
|
||||
}
|
||||
|
||||
private static class NonFinalUtilityClassVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
// no call to super, so that it doesn't drill down to inner classes
|
||||
if (!UtilityClassUtil.isUtilityClass(aClass)) {
|
||||
return;
|
||||
}
|
||||
if (aClass.hasModifierProperty(PsiModifier.FINAL) ||
|
||||
aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass, aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiField;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.MethodUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ProtectedMemberInFinalClassInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("protected.member.in.final.class.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("protected.member.in.final.class.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new ProtectedMemberInFinalClassVisitor();
|
||||
}
|
||||
|
||||
private static class ProtectedMemberInFinalClassVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NotNull PsiMethod method) {
|
||||
if (!method.hasModifierProperty(PsiModifier.PROTECTED)) {
|
||||
return;
|
||||
}
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
if (containingClass == null || !containingClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
return;
|
||||
}
|
||||
if (MethodUtils.hasSuper(method)) {
|
||||
return;
|
||||
}
|
||||
registerModifierError(PsiModifier.PROTECTED, method, PsiModifier.PROTECTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitField(@NotNull PsiField field) {
|
||||
if (!field.hasModifierProperty(PsiModifier.PROTECTED)) {
|
||||
return;
|
||||
}
|
||||
final PsiClass containingClass = field.getContainingClass();
|
||||
if (containingClass == null || !containingClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
return;
|
||||
}
|
||||
registerModifierError(PsiModifier.PROTECTED, field, PsiModifier.PROTECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.psi.PsiParameterList;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.SerializationUtils;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PublicConstructorInspectionBase extends BaseInspection {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("public.constructor.display.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String buildErrorString(Object... infos) {
|
||||
if (((Boolean)infos[0]).booleanValue()) {
|
||||
return InspectionGadgetsBundle.message("public.default.constructor.problem.descriptor");
|
||||
}
|
||||
else {
|
||||
return InspectionGadgetsBundle.message("public.constructor.problem.descriptor");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new PublicConstructorVisitor();
|
||||
}
|
||||
|
||||
private static class PublicConstructorVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
super.visitMethod(method);
|
||||
if (!method.isConstructor()) {
|
||||
return;
|
||||
}
|
||||
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
return;
|
||||
}
|
||||
final PsiClass aClass = method.getContainingClass();
|
||||
if (aClass == null || aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
return;
|
||||
}
|
||||
if (SerializationUtils.isExternalizable(aClass)) {
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
if (parameterList.getParametersCount() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
registerMethodError(method, Boolean.FALSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
super.visitClass(aClass);
|
||||
if (aClass.isInterface() || aClass.isEnum()) {
|
||||
return;
|
||||
}
|
||||
if (!aClass.hasModifierProperty(PsiModifier.PUBLIC) || aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
return;
|
||||
}
|
||||
final PsiMethod[] constructors = aClass.getConstructors();
|
||||
if (constructors.length > 0) {
|
||||
return;
|
||||
}
|
||||
if (SerializationUtils.isExternalizable(aClass)) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiModifierListOwner;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.fixes.AddToIgnoreIfAnnotatedByListQuickFix;
|
||||
import com.siyeh.ig.psiutils.UtilityClassUtil;
|
||||
import com.siyeh.ig.ui.ExternalizableStringSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class UtilityClassInspectionBase extends BaseInspection {
|
||||
@SuppressWarnings({"PublicField"})
|
||||
public final ExternalizableStringSet ignorableAnnotations = new ExternalizableStringSet();
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("utility.class.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"utility.class.problem.descriptor");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected InspectionGadgetsFix[] buildFixes(Object... infos) {
|
||||
return AddToIgnoreIfAnnotatedByListQuickFix.build((PsiModifierListOwner)infos[0], ignorableAnnotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new UtilityClassVisitor();
|
||||
}
|
||||
|
||||
private class UtilityClassVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
// no call to super, so that it doesn't drill down to inner classes
|
||||
if (!UtilityClassUtil.isUtilityClass(aClass)) {
|
||||
return;
|
||||
}
|
||||
if (AnnotationUtil.isAnnotated(aClass, ignorableAnnotations)) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass, aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.util.Query;
|
||||
import com.siyeh.HardcodedMethodConstants;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.UtilityClassUtil;
|
||||
import com.siyeh.ig.ui.ExternalizableStringSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class UtilityClassWithoutPrivateConstructorInspectionBase extends BaseInspection {
|
||||
@SuppressWarnings({"PublicField"})
|
||||
public final ExternalizableStringSet ignorableAnnotations = new ExternalizableStringSet();
|
||||
@SuppressWarnings({"PublicField"})
|
||||
public boolean ignoreClassesWithOnlyMain = false;
|
||||
|
||||
@Nullable
|
||||
static PsiMethod getNullArgConstructor(PsiClass aClass) {
|
||||
final PsiMethod[] constructors = aClass.getConstructors();
|
||||
for (final PsiMethod constructor : constructors) {
|
||||
final PsiParameterList params = constructor.getParameterList();
|
||||
if (params.getParametersCount() == 0) {
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("utility.class.without.private.constructor.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("utility.class.without.private.constructor.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new UtilityClassWithoutPrivateConstructorVisitor();
|
||||
}
|
||||
|
||||
|
||||
private class UtilityClassWithoutPrivateConstructorVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
// no call to super, so that it doesn't drill down to inner classes
|
||||
if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
return;
|
||||
}
|
||||
if (!UtilityClassUtil.isUtilityClass(aClass)) {
|
||||
return;
|
||||
}
|
||||
if (ignoreClassesWithOnlyMain && hasOnlyMain(aClass)) {
|
||||
return;
|
||||
}
|
||||
if (hasPrivateConstructor(aClass)) {
|
||||
return;
|
||||
}
|
||||
if (AnnotationUtil.isAnnotated(aClass, ignorableAnnotations)) {
|
||||
return;
|
||||
}
|
||||
if (aClass.hasModifierProperty(PsiModifier.PRIVATE) && aClass.getConstructors().length == 0) {
|
||||
return;
|
||||
}
|
||||
final SearchScope scope = GlobalSearchScope.projectScope(aClass.getProject());
|
||||
final Query<PsiClass> query = ClassInheritorsSearch.search(aClass, scope, true, true);
|
||||
final PsiClass subclass = query.findFirst();
|
||||
if (subclass != null) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass, aClass);
|
||||
}
|
||||
|
||||
private boolean hasOnlyMain(PsiClass aClass) {
|
||||
final PsiMethod[] methods = aClass.getMethods();
|
||||
if (methods.length == 0) {
|
||||
return false;
|
||||
}
|
||||
for (PsiMethod method : methods) {
|
||||
if (method.isConstructor()) {
|
||||
continue;
|
||||
}
|
||||
if (!method.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
return false;
|
||||
}
|
||||
if (method.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
continue;
|
||||
}
|
||||
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
return false;
|
||||
}
|
||||
final String name = method.getName();
|
||||
if (!name.equals(HardcodedMethodConstants.MAIN)) {
|
||||
return false;
|
||||
}
|
||||
final PsiType returnType = method.getReturnType();
|
||||
if (!PsiType.VOID.equals(returnType)) {
|
||||
return false;
|
||||
}
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
if (parameterList.getParametersCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
final PsiParameter[] parameters = parameterList.getParameters();
|
||||
final PsiParameter parameter = parameters[0];
|
||||
final PsiType type = parameter.getType();
|
||||
if (!type.equalsToText("java.lang.String[]")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean hasPrivateConstructor(PsiClass aClass) {
|
||||
final PsiMethod[] constructors = aClass.getConstructors();
|
||||
for (final PsiMethod constructor : constructors) {
|
||||
if (constructor.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.errorhandling;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiCatchSection;
|
||||
import com.intellij.psi.PsiParameter;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.PsiTypeElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.ui.ExternalizableStringSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BadExceptionCaughtInspectionBase extends BaseInspection {
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
public final ExternalizableStringSet exceptions =
|
||||
new ExternalizableStringSet(
|
||||
"java.lang.NullPointerException",
|
||||
"java.lang.IllegalMonitorStateException",
|
||||
"java.lang.ArrayIndexOutOfBoundsException"
|
||||
);
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
public String exceptionsString = "";
|
||||
|
||||
public BadExceptionCaughtInspectionBase() {
|
||||
if (!exceptionsString.isEmpty()) {
|
||||
exceptions.clear();
|
||||
final List<String> strings = StringUtil.split(exceptionsString, ",");
|
||||
for (String string : strings) {
|
||||
exceptions.add(string);
|
||||
}
|
||||
exceptionsString = "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return "ProhibitedExceptionCaught";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("bad.exception.caught.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("bad.exception.caught.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new BadExceptionCaughtVisitor();
|
||||
}
|
||||
|
||||
private class BadExceptionCaughtVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitCatchSection(PsiCatchSection section) {
|
||||
super.visitCatchSection(section);
|
||||
final PsiParameter parameter = section.getParameter();
|
||||
if (parameter == null) {
|
||||
return;
|
||||
}
|
||||
final PsiTypeElement typeElement = parameter.getTypeElement();
|
||||
if (typeElement == null) {
|
||||
return;
|
||||
}
|
||||
final PsiTypeElement[] childTypeElements = PsiTreeUtil.getChildrenOfType(typeElement, PsiTypeElement.class);
|
||||
if (childTypeElements != null) {
|
||||
for (PsiTypeElement childTypeElement : childTypeElements) {
|
||||
checkTypeElement(childTypeElement);
|
||||
}
|
||||
}
|
||||
else {
|
||||
checkTypeElement(typeElement);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkTypeElement(PsiTypeElement typeElement) {
|
||||
final PsiType type = typeElement.getType();
|
||||
if (exceptions.contains(type.getCanonicalText())) {
|
||||
registerError(typeElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.errorhandling;
|
||||
|
||||
import com.intellij.codeInsight.TestFrameworks;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.LibraryUtil;
|
||||
import com.siyeh.ig.ui.ExternalizableStringSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BadExceptionDeclaredInspectionBase extends BaseInspection {
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
public final ExternalizableStringSet exceptions =
|
||||
new ExternalizableStringSet(
|
||||
"java.lang.Throwable",
|
||||
"java.lang.Exception",
|
||||
"java.lang.Error",
|
||||
"java.lang.RuntimeException",
|
||||
"java.lang.NullPointerException",
|
||||
"java.lang.ClassCastException",
|
||||
"java.lang.ArrayIndexOutOfBoundsException"
|
||||
);
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
public String exceptionsString = "";
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
public boolean ignoreTestCases = false;
|
||||
public boolean ignoreLibraryOverrides = false;
|
||||
|
||||
public BadExceptionDeclaredInspectionBase() {
|
||||
if (!exceptionsString.isEmpty()) {
|
||||
exceptions.clear();
|
||||
final List<String> strings = StringUtil.split(exceptionsString, ",");
|
||||
for (String string : strings) {
|
||||
exceptions.add(string);
|
||||
}
|
||||
exceptionsString = "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return "ProhibitedExceptionDeclared";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("bad.exception.declared.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("bad.exception.declared.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new BadExceptionDeclaredVisitor();
|
||||
}
|
||||
|
||||
private class BadExceptionDeclaredVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NotNull PsiMethod method) {
|
||||
super.visitMethod(method);
|
||||
if (ignoreTestCases) {
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
final TestFrameworks testFrameworks = TestFrameworks.getInstance();
|
||||
if (containingClass != null && testFrameworks.isTestOrConfig(containingClass)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ignoreLibraryOverrides && LibraryUtil.isOverrideOfLibraryMethod(method)) {
|
||||
return;
|
||||
}
|
||||
final PsiReferenceList throwsList = method.getThrowsList();
|
||||
final PsiJavaCodeReferenceElement[] references = throwsList.getReferenceElements();
|
||||
for (PsiJavaCodeReferenceElement reference : references) {
|
||||
final PsiElement element = reference.resolve();
|
||||
if (!(element instanceof PsiClass)) {
|
||||
continue;
|
||||
}
|
||||
final PsiClass thrownClass = (PsiClass)element;
|
||||
final String qualifiedName = thrownClass.getQualifiedName();
|
||||
if (qualifiedName != null && exceptions.contains(qualifiedName)) {
|
||||
registerError(reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.errorhandling;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.PsiThrowStatement;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.ui.ExternalizableStringSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BadExceptionThrownInspectionBase extends BaseInspection {
|
||||
@SuppressWarnings("PublicField")
|
||||
public final ExternalizableStringSet exceptions =
|
||||
new ExternalizableStringSet(
|
||||
"java.lang.Throwable",
|
||||
"java.lang.Exception",
|
||||
"java.lang.Error",
|
||||
"java.lang.RuntimeException",
|
||||
"java.lang.NullPointerException",
|
||||
"java.lang.ClassCastException",
|
||||
"java.lang.ArrayIndexOutOfBoundsException"
|
||||
);
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
public String exceptionsString = "";
|
||||
|
||||
public BadExceptionThrownInspectionBase() {
|
||||
if (!exceptionsString.isEmpty()) {
|
||||
exceptions.clear();
|
||||
final List<String> strings =
|
||||
StringUtil.split(exceptionsString, ",");
|
||||
for (String string : strings) {
|
||||
exceptions.add(string);
|
||||
}
|
||||
exceptionsString = "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return "ProhibitedExceptionThrown";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"bad.exception.thrown.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
final PsiType type = (PsiType)infos[0];
|
||||
final String exceptionName = type.getPresentableText();
|
||||
return InspectionGadgetsBundle.message(
|
||||
"bad.exception.thrown.problem.descriptor", exceptionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new BadExceptionThrownVisitor();
|
||||
}
|
||||
|
||||
private class BadExceptionThrownVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitThrowStatement(PsiThrowStatement statement) {
|
||||
super.visitThrowStatement(statement);
|
||||
final PsiExpression exception = statement.getException();
|
||||
if (exception == null) {
|
||||
return;
|
||||
}
|
||||
final PsiType type = exception.getType();
|
||||
if (type == null) {
|
||||
return;
|
||||
}
|
||||
final String text = type.getCanonicalText();
|
||||
if (exceptions.contains(text)) {
|
||||
registerStatementError(statement, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.errorhandling;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ThrowsRuntimeExceptionInspectionBase extends BaseInspection {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("throws.runtime.exception.display.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("throws.runtime.exception.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new ThrowsRuntimeExceptionVisitor();
|
||||
}
|
||||
|
||||
private static class ThrowsRuntimeExceptionVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
super.visitMethod(method);
|
||||
final PsiReferenceList throwsList = method.getThrowsList();
|
||||
final PsiJavaCodeReferenceElement[] referenceElements = throwsList.getReferenceElements();
|
||||
for (PsiJavaCodeReferenceElement referenceElement : referenceElements) {
|
||||
final PsiElement target = referenceElement.resolve();
|
||||
if (!(target instanceof PsiClass)) {
|
||||
continue;
|
||||
}
|
||||
final PsiClass aClass = (PsiClass)target;
|
||||
if (!InheritanceUtil.isInheritor(aClass, "java.lang.RuntimeException")) {
|
||||
continue;
|
||||
}
|
||||
final String className = aClass.getName();
|
||||
registerError(referenceElement, className, referenceElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.errorhandling;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.ClassUtils;
|
||||
import com.siyeh.ig.psiutils.ExceptionUtils;
|
||||
import com.siyeh.ig.psiutils.TestUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class TooBroadCatchInspectionBase extends BaseInspection {
|
||||
@SuppressWarnings({"PublicField"})
|
||||
public boolean onlyWarnOnRootExceptions = false;
|
||||
@SuppressWarnings("PublicField")
|
||||
public boolean ignoreInTestCode = false;
|
||||
@SuppressWarnings("PublicField")
|
||||
public boolean ignoreThrown = false;
|
||||
|
||||
protected static TextRange getRangeToSelect(PsiCodeBlock block) {
|
||||
PsiElement first = block.getFirstBodyElement();
|
||||
if (first instanceof PsiWhiteSpace) {
|
||||
first = first.getNextSibling();
|
||||
}
|
||||
if (first == null) {
|
||||
final int offset = block.getTextRange().getStartOffset() + 1;
|
||||
return new TextRange(offset, offset);
|
||||
}
|
||||
PsiElement last = block.getLastBodyElement();
|
||||
if (last instanceof PsiWhiteSpace) {
|
||||
last = last.getPrevSibling();
|
||||
}
|
||||
final TextRange textRange;
|
||||
if (last == null) {
|
||||
textRange = first.getTextRange();
|
||||
}
|
||||
else {
|
||||
textRange = last.getTextRange();
|
||||
}
|
||||
return new TextRange(first.getTextRange().getStartOffset(), textRange.getEndOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return "OverlyBroadCatchBlock";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("too.broad.catch.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
final List<PsiClass> typesMasked = (List<PsiClass>)infos[0];
|
||||
String typesMaskedString = typesMasked.get(0).getName();
|
||||
if (typesMasked.size() == 1) {
|
||||
return InspectionGadgetsBundle.message("too.broad.catch.problem.descriptor", typesMaskedString);
|
||||
}
|
||||
else {
|
||||
//Collections.sort(typesMasked);
|
||||
final int lastTypeIndex = typesMasked.size() - 1;
|
||||
for (int i = 1; i < lastTypeIndex; i++) {
|
||||
typesMaskedString += ", ";
|
||||
typesMaskedString += typesMasked.get(i).getName();
|
||||
}
|
||||
final String lastTypeString = typesMasked.get(lastTypeIndex).getName();
|
||||
return InspectionGadgetsBundle.message("too.broad.catch.problem.descriptor1", typesMaskedString, lastTypeString);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new TooBroadCatchVisitor();
|
||||
}
|
||||
|
||||
private class TooBroadCatchVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitTryStatement(@NotNull PsiTryStatement statement) {
|
||||
super.visitTryStatement(statement);
|
||||
final PsiCodeBlock tryBlock = statement.getTryBlock();
|
||||
if (tryBlock == null) {
|
||||
return;
|
||||
}
|
||||
if (ignoreInTestCode && TestUtils.isInTestCode(statement)) {
|
||||
return;
|
||||
}
|
||||
final Set<PsiClassType> thrownTypes = ExceptionUtils.calculateExceptionsThrown(tryBlock);
|
||||
final Set<PsiType> caughtTypes = new HashSet<PsiType>(thrownTypes.size());
|
||||
final PsiCatchSection[] catchSections = statement.getCatchSections();
|
||||
for (final PsiCatchSection catchSection : catchSections) {
|
||||
final PsiParameter parameter = catchSection.getParameter();
|
||||
if (parameter == null) {
|
||||
continue;
|
||||
}
|
||||
final PsiType caughtType = parameter.getType();
|
||||
if (caughtType instanceof PsiDisjunctionType) {
|
||||
final PsiDisjunctionType disjunctionType = (PsiDisjunctionType)caughtType;
|
||||
final List<PsiType> types = disjunctionType.getDisjunctions();
|
||||
for (PsiType type : types) {
|
||||
check(thrownTypes, caughtTypes, parameter, type);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (thrownTypes.isEmpty()) {
|
||||
if (CommonClassNames.JAVA_LANG_EXCEPTION.equals(caughtType.getCanonicalText())) {
|
||||
final PsiTypeElement typeElement = parameter.getTypeElement();
|
||||
if (typeElement == null) {
|
||||
continue;
|
||||
}
|
||||
final PsiClass runtimeExceptionClass = ClassUtils.findClass(CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION, parameter);
|
||||
registerError(typeElement, Collections.singletonList(runtimeExceptionClass));
|
||||
}
|
||||
}
|
||||
else {
|
||||
check(thrownTypes, caughtTypes, parameter, caughtType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void check(Set<PsiClassType> thrownTypes, Set<PsiType> caughtTypes, PsiParameter parameter, PsiType caughtType) {
|
||||
final List<PsiClass> maskedExceptions = findMaskedExceptions(thrownTypes, caughtTypes, caughtType);
|
||||
if (maskedExceptions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final PsiTypeElement typeElement = parameter.getTypeElement();
|
||||
if (typeElement == null) {
|
||||
return;
|
||||
}
|
||||
registerError(typeElement, maskedExceptions);
|
||||
}
|
||||
|
||||
private List<PsiClass> findMaskedExceptions(Set<PsiClassType> thrownTypes, Set<PsiType> caughtTypes, PsiType caughtType) {
|
||||
if (thrownTypes.contains(caughtType)) {
|
||||
if (ignoreThrown) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
caughtTypes.add(caughtType);
|
||||
thrownTypes.remove(caughtType);
|
||||
}
|
||||
if (onlyWarnOnRootExceptions) {
|
||||
if (!ExceptionUtils.isGenericExceptionClass(caughtType)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
final List<PsiClass> maskedTypes = new ArrayList();
|
||||
for (PsiClassType typeThrown : thrownTypes) {
|
||||
if (!caughtTypes.contains(typeThrown) && caughtType.isAssignableFrom(typeThrown)) {
|
||||
caughtTypes.add(typeThrown);
|
||||
final PsiClass aClass = typeThrown.resolve();
|
||||
if (aClass != null) {
|
||||
maskedTypes.add(aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
return maskedTypes;
|
||||
}
|
||||
}
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.errorhandling;
|
||||
|
||||
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.TestUtils;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class UnusedCatchParameterInspectionBase extends BaseInspection {
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
public boolean m_ignoreCatchBlocksWithComments = false;
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
public boolean m_ignoreTestCases = false;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"unused.catch.parameter.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
final MultipleCheckboxOptionsPanel optionsPanel =
|
||||
new MultipleCheckboxOptionsPanel(this);
|
||||
optionsPanel.addCheckbox(InspectionGadgetsBundle.message(
|
||||
"unused.catch.parameter.ignore.catch.option"),
|
||||
"m_ignoreCatchBlocksWithComments");
|
||||
optionsPanel.addCheckbox(InspectionGadgetsBundle.message(
|
||||
"unused.catch.parameter.ignore.empty.option"),
|
||||
"m_ignoreTestCases");
|
||||
return optionsPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
final boolean namedIgnoreButUsed = ((Boolean)infos[0]).booleanValue();
|
||||
if (namedIgnoreButUsed) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"used.catch.parameter.named.ignore.problem.descriptor"
|
||||
);
|
||||
}
|
||||
return InspectionGadgetsBundle.message(
|
||||
"unused.catch.parameter.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new UnusedCatchParameterVisitor();
|
||||
}
|
||||
|
||||
private class UnusedCatchParameterVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitTryStatement(@NotNull PsiTryStatement statement) {
|
||||
super.visitTryStatement(statement);
|
||||
if (m_ignoreTestCases && TestUtils.isInTestCode(statement)) {
|
||||
return;
|
||||
}
|
||||
final PsiCatchSection[] catchSections = statement.getCatchSections();
|
||||
for (PsiCatchSection catchSection : catchSections) {
|
||||
checkCatchSection(catchSection);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCatchSection(PsiCatchSection section) {
|
||||
final PsiParameter parameter = section.getParameter();
|
||||
if (parameter == null) {
|
||||
return;
|
||||
}
|
||||
@NonNls final String parameterName = parameter.getName();
|
||||
final PsiCodeBlock block = section.getCatchBlock();
|
||||
if (block == null) {
|
||||
return;
|
||||
}
|
||||
if (m_ignoreCatchBlocksWithComments) {
|
||||
final PsiElement[] children = block.getChildren();
|
||||
for (final PsiElement child : children) {
|
||||
if (child instanceof PsiComment) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
final CatchParameterUsedVisitor visitor =
|
||||
new CatchParameterUsedVisitor(parameter);
|
||||
block.accept(visitor);
|
||||
final boolean namedIgnore = PsiUtil.isIgnoredName(parameterName);
|
||||
if (visitor.isUsed()) {
|
||||
if (namedIgnore) {
|
||||
registerVariableError(parameter, Boolean.TRUE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (namedIgnore) {
|
||||
return;
|
||||
}
|
||||
registerVariableError(parameter, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.imports;
|
||||
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.util.FileTypeUtils;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.OrderedSet;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.psiutils.StringUtils;
|
||||
import com.siyeh.ig.psiutils.TestUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class StaticImportInspectionBase extends BaseInspection {
|
||||
@SuppressWarnings({"PublicField"}) public boolean ignoreSingleFieldImports = false;
|
||||
@SuppressWarnings({"PublicField"}) public boolean ignoreSingeMethodImports = false;
|
||||
@SuppressWarnings("PublicField") public boolean ignoreInTestCode = false;
|
||||
@SuppressWarnings("PublicField") public OrderedSet<String> allowedClasses = new OrderedSet<String>();
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("static.import.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"static.import.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
return new StaticImportFix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new StaticImportVisitor();
|
||||
}
|
||||
|
||||
private static class StaticImportFix extends InspectionGadgetsFix {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message("static.import.replace.quickfix");
|
||||
}
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
|
||||
final PsiImportStaticStatement importStatement = (PsiImportStaticStatement)descriptor.getPsiElement();
|
||||
final PsiJavaCodeReferenceElement importReference = importStatement.getImportReference();
|
||||
if (importReference == null) {
|
||||
return;
|
||||
}
|
||||
final JavaResolveResult[] importTargets = importReference.multiResolve(false);
|
||||
if (importTargets.length == 0) {
|
||||
return;
|
||||
}
|
||||
final boolean onDemand = importStatement.isOnDemand();
|
||||
final StaticImportFix.StaticImportReferenceCollector
|
||||
referenceCollector = new StaticImportFix.StaticImportReferenceCollector(importTargets, onDemand);
|
||||
final PsiJavaFile file = (PsiJavaFile)importStatement.getContainingFile();
|
||||
file.accept(referenceCollector);
|
||||
final List<PsiJavaCodeReferenceElement> references = referenceCollector.getReferences();
|
||||
final Map<PsiJavaCodeReferenceElement, PsiMember> referenceTargetMap = new HashMap<PsiJavaCodeReferenceElement, PsiMember>();
|
||||
for (PsiJavaCodeReferenceElement reference : references) {
|
||||
final PsiElement target = reference.resolve();
|
||||
if (target instanceof PsiMember) {
|
||||
final PsiMember member = (PsiMember)target;
|
||||
referenceTargetMap.put(reference, member);
|
||||
}
|
||||
}
|
||||
importStatement.delete();
|
||||
for (Map.Entry<PsiJavaCodeReferenceElement, PsiMember> entry : referenceTargetMap.entrySet()) {
|
||||
removeReference(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeReference(PsiJavaCodeReferenceElement reference, PsiMember target) {
|
||||
final PsiManager manager = reference.getManager();
|
||||
final Project project = manager.getProject();
|
||||
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
|
||||
final PsiElementFactory factory = psiFacade.getElementFactory();
|
||||
final PsiClass aClass = target.getContainingClass();
|
||||
if (aClass == null) {
|
||||
return;
|
||||
}
|
||||
final String qualifiedName = aClass.getQualifiedName();
|
||||
final String text = reference.getText();
|
||||
final String referenceText = qualifiedName + '.' + text;
|
||||
if (reference instanceof PsiReferenceExpression) {
|
||||
final PsiExpression newReference = factory.createExpressionFromText(referenceText, reference);
|
||||
final PsiElement insertedElement = reference.replace(newReference);
|
||||
JavaCodeStyleManager.getInstance(project).shortenClassReferences(insertedElement);
|
||||
}
|
||||
else {
|
||||
final PsiJavaCodeReferenceElement referenceElement =
|
||||
factory.createReferenceElementByFQClassName(referenceText, reference.getResolveScope());
|
||||
final PsiElement insertedElement = reference.replace(referenceElement);
|
||||
JavaCodeStyleManager.getInstance(project).shortenClassReferences(insertedElement);
|
||||
}
|
||||
}
|
||||
|
||||
static class StaticImportReferenceCollector extends JavaRecursiveElementVisitor {
|
||||
|
||||
private final JavaResolveResult[] importTargets;
|
||||
private final boolean onDemand;
|
||||
private final List<PsiJavaCodeReferenceElement> references = new ArrayList<PsiJavaCodeReferenceElement>();
|
||||
|
||||
StaticImportReferenceCollector(@NotNull JavaResolveResult[] importTargets, boolean onDemand) {
|
||||
this.importTargets = importTargets;
|
||||
this.onDemand = onDemand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
|
||||
super.visitReferenceElement(reference);
|
||||
if (isFullyQualifiedReference(reference)) {
|
||||
return;
|
||||
}
|
||||
PsiElement parent = reference.getParent();
|
||||
if (parent instanceof PsiImportStatementBase) {
|
||||
return;
|
||||
}
|
||||
while (parent instanceof PsiJavaCodeReferenceElement) {
|
||||
parent = parent.getParent();
|
||||
if (parent instanceof PsiImportStatementBase) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
checkStaticImportReference(reference);
|
||||
}
|
||||
|
||||
private void checkStaticImportReference(PsiJavaCodeReferenceElement reference) {
|
||||
if (reference.isQualified()) {
|
||||
return;
|
||||
}
|
||||
final PsiElement target = reference.resolve();
|
||||
if (!(target instanceof PsiMethod) && !(target instanceof PsiClass) && !(target instanceof PsiField)) {
|
||||
return;
|
||||
}
|
||||
final PsiMember member = (PsiMember)target;
|
||||
for (JavaResolveResult importTarget : importTargets) {
|
||||
final PsiElement targetElement = importTarget.getElement();
|
||||
if (targetElement instanceof PsiMethod || targetElement instanceof PsiField) {
|
||||
if (member.equals(targetElement)) {
|
||||
addReference(reference);
|
||||
}
|
||||
}
|
||||
else if (targetElement instanceof PsiClass) {
|
||||
if (onDemand) {
|
||||
final PsiClass containingClass = member.getContainingClass();
|
||||
if (InheritanceUtil.isInheritorOrSelf((PsiClass)targetElement, containingClass, true)) {
|
||||
addReference(reference);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (targetElement.equals(member)) {
|
||||
addReference(reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addReference(PsiJavaCodeReferenceElement reference) {
|
||||
references.add(reference);
|
||||
}
|
||||
|
||||
public List<PsiJavaCodeReferenceElement> getReferences() {
|
||||
return references;
|
||||
}
|
||||
|
||||
public static boolean isFullyQualifiedReference(PsiJavaCodeReferenceElement reference) {
|
||||
if (!reference.isQualified()) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement directParent = reference.getParent();
|
||||
if (directParent instanceof PsiMethodCallExpression ||
|
||||
directParent instanceof PsiAssignmentExpression ||
|
||||
directParent instanceof PsiVariable) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement parent =
|
||||
PsiTreeUtil.getParentOfType(reference, PsiImportStatementBase.class, PsiPackageStatement.class, JavaCodeFragment.class);
|
||||
if (parent != null) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement target = reference.resolve();
|
||||
if (!(target instanceof PsiClass)) {
|
||||
return false;
|
||||
}
|
||||
final PsiClass aClass = (PsiClass)target;
|
||||
final String fqName = aClass.getQualifiedName();
|
||||
if (fqName == null) {
|
||||
return false;
|
||||
}
|
||||
final String text =
|
||||
StringUtils.stripAngleBrackets(reference.getText());
|
||||
return text.equals(fqName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class StaticImportVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
final PsiElement parent = aClass.getParent();
|
||||
if (!(parent instanceof PsiJavaFile)) {
|
||||
return;
|
||||
}
|
||||
final PsiJavaFile file = (PsiJavaFile)parent;
|
||||
if (FileTypeUtils.isInServerPageFile(file)) {
|
||||
return;
|
||||
}
|
||||
if (!file.getClasses()[0].equals(aClass)) {
|
||||
return;
|
||||
}
|
||||
final PsiImportList importList = file.getImportList();
|
||||
if (importList == null) {
|
||||
return;
|
||||
}
|
||||
if (ignoreInTestCode && TestUtils.isTest(aClass)) {
|
||||
return;
|
||||
}
|
||||
final PsiImportStaticStatement[] importStatements = importList.getImportStaticStatements();
|
||||
for (PsiImportStaticStatement importStatement : importStatements) {
|
||||
if (shouldReportImportStatement(importStatement)) {
|
||||
registerError(importStatement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldReportImportStatement(PsiImportStaticStatement importStatement) {
|
||||
final PsiJavaCodeReferenceElement importReference = importStatement.getImportReference();
|
||||
if (importReference == null) {
|
||||
return false;
|
||||
}
|
||||
PsiClass targetClass = importStatement.resolveTargetClass();
|
||||
boolean checked = false;
|
||||
while (targetClass != null) {
|
||||
final String qualifiedName = targetClass.getQualifiedName();
|
||||
if (allowedClasses.contains(qualifiedName)) {
|
||||
return false;
|
||||
}
|
||||
if (checked) {
|
||||
break;
|
||||
}
|
||||
targetClass = targetClass.getContainingClass();
|
||||
checked = true;
|
||||
}
|
||||
if (importStatement.isOnDemand()) {
|
||||
return true;
|
||||
}
|
||||
if (ignoreSingleFieldImports || ignoreSingeMethodImports) {
|
||||
boolean field = false;
|
||||
boolean method = false;
|
||||
// in the presence of method overloading the plain resolve() method returns null
|
||||
final JavaResolveResult[] results = importReference.multiResolve(false);
|
||||
for (JavaResolveResult result : results) {
|
||||
final PsiElement element = result.getElement();
|
||||
if (element instanceof PsiField) {
|
||||
field = true;
|
||||
} else if (element instanceof PsiMethod) {
|
||||
method = true;
|
||||
}
|
||||
}
|
||||
if (field && !method) {
|
||||
if (ignoreSingleFieldImports) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (method && !field) {
|
||||
if (ignoreSingeMethodImports) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.siyeh.ig.inheritance;
|
||||
|
||||
import com.intellij.psi.PsiAnonymousClass;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.CollectionUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ExtendsConcreteCollectionInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return "ClassExtendsConcreteCollection";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"extends.concrete.collection.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
final PsiClass superClass = (PsiClass)infos[0];
|
||||
final PsiClass aClass = (PsiClass)infos[1];
|
||||
if (aClass instanceof PsiAnonymousClass) {
|
||||
return InspectionGadgetsBundle.message("anonymous.extends.concrete.collection.problem.descriptor", superClass.getQualifiedName());
|
||||
} else {
|
||||
return InspectionGadgetsBundle.message("extends.concrete.collection.problem.descriptor", superClass.getQualifiedName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new ExtendsConcreteCollectionVisitor();
|
||||
}
|
||||
|
||||
private static class ExtendsConcreteCollectionVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
if (aClass.isInterface() || aClass.isAnnotationType() || aClass.isEnum()) {
|
||||
return;
|
||||
}
|
||||
final PsiClass superClass = aClass.getSuperClass();
|
||||
if (superClass == null) {
|
||||
return;
|
||||
}
|
||||
if (!CollectionUtils.isCollectionClass(superClass)) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass, superClass, aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
-32
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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,31 +23,28 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.DebugUtil;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.ui.GuiUtils;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Query;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.psiutils.ClassUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* User: cdr
|
||||
*/
|
||||
class StaticInheritanceFix extends InspectionGadgetsFix {
|
||||
private static final Logger LOG = Logger.getInstance("#com.siyeh.ig.inheritance.StaticInheritanceFix");
|
||||
private final boolean myReplaceInWholeProject;
|
||||
|
||||
StaticInheritanceFix(boolean replaceInWholeProject) {
|
||||
@@ -101,13 +98,20 @@ class StaticInheritanceFix extends InspectionGadgetsFix {
|
||||
}
|
||||
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)reference;
|
||||
if (!myReplaceInWholeProject) {
|
||||
PsiClass aClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class);
|
||||
boolean isInheritor = false;
|
||||
while (aClass != null) {
|
||||
isInheritor = InheritanceUtil.isInheritorOrSelf(aClass, implementingClass, true);
|
||||
if (isInheritor) break;
|
||||
aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class);
|
||||
}
|
||||
boolean isInheritor =
|
||||
ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
boolean isInheritor = false;
|
||||
PsiClass aClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class);
|
||||
while (aClass != null) {
|
||||
isInheritor = InheritanceUtil.isInheritorOrSelf(aClass, implementingClass, true);
|
||||
if (isInheritor) break;
|
||||
aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class);
|
||||
}
|
||||
return isInheritor;
|
||||
}
|
||||
});
|
||||
if (!isInheritor) continue;
|
||||
}
|
||||
final Runnable runnable = new Runnable() {
|
||||
@@ -144,24 +148,16 @@ class StaticInheritanceFix extends InspectionGadgetsFix {
|
||||
}
|
||||
|
||||
private static void invokeWriteAction(final Runnable runnable, final PsiFile file) {
|
||||
try {
|
||||
GuiUtils.runOrInvokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new WriteCommandAction(file.getProject(), file) {
|
||||
@Override
|
||||
protected void run(Result result) throws Throwable {
|
||||
runnable.run();
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new WriteCommandAction(file.getProject(), file) {
|
||||
@Override
|
||||
protected void run(Result result) throws Throwable {
|
||||
runnable.run();
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user