use of gnu.trove.THashMap in project intellij-community by JetBrains.
the class RedundantSuppressInspectionBase method checkElement.
@NotNull
public ProblemDescriptor[] checkElement(@NotNull final PsiElement psiElement, @NotNull final InspectionManager manager) {
final Map<PsiElement, Collection<String>> suppressedScopes = new THashMap<>();
psiElement.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitModifierList(PsiModifierList list) {
super.visitModifierList(list);
final PsiElement parent = list.getParent();
if (parent instanceof PsiModifierListOwner && !(parent instanceof PsiClass)) {
checkElement(parent);
}
}
@Override
public void visitComment(PsiComment comment) {
checkElement(comment);
}
@Override
public void visitClass(PsiClass aClass) {
if (aClass == psiElement) {
super.visitClass(aClass);
checkElement(aClass);
}
}
private void checkElement(final PsiElement owner) {
String idsString = JavaSuppressionUtil.getSuppressedInspectionIdsIn(owner);
if (idsString != null && !idsString.isEmpty()) {
List<String> ids = StringUtil.split(idsString, ",");
if (IGNORE_ALL && (ids.contains(SuppressionUtil.ALL) || ids.contains(SuppressionUtil.ALL.toLowerCase())))
return;
Collection<String> suppressed = suppressedScopes.get(owner);
if (suppressed == null) {
suppressed = ids;
} else {
for (String id : ids) {
if (!suppressed.contains(id)) {
suppressed.add(id);
}
}
}
suppressedScopes.put(owner, suppressed);
}
}
});
if (suppressedScopes.values().isEmpty())
return ProblemDescriptor.EMPTY_ARRAY;
// have to visit all file from scratch since inspections can be written in any pervasive way including checkFile() overriding
Map<InspectionToolWrapper, String> suppressedTools = new THashMap<>();
InspectionToolWrapper[] toolWrappers = getInspectionTools(psiElement, manager);
for (Collection<String> ids : suppressedScopes.values()) {
for (Iterator<String> iterator = ids.iterator(); iterator.hasNext(); ) {
final String shortName = iterator.next().trim();
for (InspectionToolWrapper toolWrapper : toolWrappers) {
if (toolWrapper instanceof LocalInspectionToolWrapper && (((LocalInspectionToolWrapper) toolWrapper).getTool().getID().equals(shortName) || shortName.equals(((LocalInspectionToolWrapper) toolWrapper).getTool().getAlternativeID()))) {
if (((LocalInspectionToolWrapper) toolWrapper).isUnfair()) {
iterator.remove();
break;
} else {
suppressedTools.put(toolWrapper, shortName);
}
} else if (toolWrapper.getShortName().equals(shortName)) {
//ignore global unused as it won't be checked anyway
if (toolWrapper instanceof LocalInspectionToolWrapper || toolWrapper instanceof GlobalInspectionToolWrapper && !((GlobalInspectionToolWrapper) toolWrapper).getTool().isGraphNeeded()) {
suppressedTools.put(toolWrapper, shortName);
} else {
iterator.remove();
break;
}
}
}
}
}
PsiFile file = psiElement.getContainingFile();
final AnalysisScope scope = new AnalysisScope(file);
final GlobalInspectionContextBase globalContext = createContext(file);
globalContext.setCurrentScope(scope);
final RefManagerImpl refManager = (RefManagerImpl) globalContext.getRefManager();
refManager.inspectionReadActionStarted();
final List<ProblemDescriptor> result;
try {
result = new ArrayList<>();
for (InspectionToolWrapper toolWrapper : suppressedTools.keySet()) {
String toolId = suppressedTools.get(toolWrapper);
toolWrapper.initialize(globalContext);
final Collection<CommonProblemDescriptor> descriptors;
if (toolWrapper instanceof LocalInspectionToolWrapper) {
LocalInspectionToolWrapper local = (LocalInspectionToolWrapper) toolWrapper;
//cant't work with passes other than LocalInspectionPass
if (local.isUnfair())
continue;
List<ProblemDescriptor> results = local.getTool().processFile(file, manager);
descriptors = new ArrayList<>(results);
} else if (toolWrapper instanceof GlobalInspectionToolWrapper) {
final GlobalInspectionToolWrapper global = (GlobalInspectionToolWrapper) toolWrapper;
GlobalInspectionTool globalTool = global.getTool();
//when graph is needed, results probably depend on outer files so absence of results on one file (in current context) doesn't guarantee anything
if (globalTool.isGraphNeeded())
continue;
descriptors = new ArrayList<>();
globalContext.getRefManager().iterate(new RefVisitor() {
@Override
public void visitElement(@NotNull RefEntity refEntity) {
CommonProblemDescriptor[] descriptors1 = global.getTool().checkElement(refEntity, scope, manager, globalContext, new ProblemDescriptionsProcessor() {
});
if (descriptors1 != null) {
ContainerUtil.addAll(descriptors, descriptors1);
}
}
});
} else {
continue;
}
for (PsiElement suppressedScope : suppressedScopes.keySet()) {
Collection<String> suppressedIds = suppressedScopes.get(suppressedScope);
if (!suppressedIds.contains(toolId))
continue;
for (CommonProblemDescriptor descriptor : descriptors) {
if (!(descriptor instanceof ProblemDescriptor))
continue;
PsiElement element = ((ProblemDescriptor) descriptor).getPsiElement();
if (element == null)
continue;
PsiElement annotation = JavaSuppressionUtil.getElementToolSuppressedIn(element, toolId);
if (annotation != null && PsiTreeUtil.isAncestor(suppressedScope, annotation, false) || annotation == null && !PsiTreeUtil.isAncestor(suppressedScope, element, false)) {
suppressedIds.remove(toolId);
break;
}
}
}
}
for (PsiElement suppressedScope : suppressedScopes.keySet()) {
Collection<String> suppressedIds = suppressedScopes.get(suppressedScope);
for (String toolId : suppressedIds) {
PsiJavaDocumentedElement psiMember;
String problemLine = null;
if (suppressedScope instanceof PsiJavaDocumentedElement) {
psiMember = (PsiJavaDocumentedElement) suppressedScope;
} else {
psiMember = PsiTreeUtil.getParentOfType(suppressedScope, PsiJavaDocumentedElement.class);
final PsiStatement statement = PsiTreeUtil.getNextSiblingOfType(suppressedScope, PsiStatement.class);
problemLine = statement != null ? statement.getText() : null;
}
if (psiMember != null && psiMember.isValid()) {
String description = InspectionsBundle.message("inspection.redundant.suppression.description");
if (myQuickFixes == null)
myQuickFixes = new BidirectionalMap<>();
final String key = toolId + (problemLine != null ? ";" + problemLine : "");
QuickFix fix = myQuickFixes.get(key);
if (fix == null) {
fix = new RemoveSuppressWarningAction(toolId, problemLine);
myQuickFixes.put(key, fix);
}
PsiElement identifier;
if (!(suppressedScope instanceof PsiJavaDocumentedElement)) {
identifier = suppressedScope;
} else {
identifier = psiMember.getNameIdentifier();
}
if (identifier == null) {
identifier = psiMember;
}
result.add(manager.createProblemDescriptor(identifier, description, (LocalQuickFix) fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false));
}
}
}
} finally {
refManager.inspectionReadActionFinished();
globalContext.close(true);
}
return result.toArray(new ProblemDescriptor[result.size()]);
}
use of gnu.trove.THashMap in project intellij-community by JetBrains.
the class ControlFlowUtil method hasObservableThrowExitPoints.
/**
* Detect throw instructions which might affect observable control flow via side effects with local variables.
*
* The side effect of exception thrown occurs when a local variable is written in the try block, and then accessed
* in the finally section or in/after a catch section.
*
* Example:
* <pre>
* { // --- start of theOuterBlock ---
* Status status = STARTED;
* try { // --- start of theTryBlock ---
* status = PREPARING;
* doPrepare(); // may throw exception
* status = WORKING;
* doWork(); // may throw exception
* status = FINISHED;
* } // --- end of theTryBlock ---
* catch (Exception e) {
* LOG.error("Failed when " + status, e); // can get PREPARING or WORKING here
* }
* if (status == FINISHED) LOG.info("Finished"); // can get PREPARING or WORKING here in the case of exception
* } // --- end of theOuterBlock ---
* </pre>
* In the example above {@code hasObservableThrowExitPoints(theTryBlock) == true},
* because the resulting value of the "status" variable depends on the exceptions being thrown.
* In the same example {@code hasObservableThrowExitPoints(theOuterBlock) == false},
* because no outgoing variables here depend on the exceptions being thrown.
*/
public static boolean hasObservableThrowExitPoints(@NotNull final ControlFlow flow, final int flowStart, final int flowEnd, @NotNull PsiElement[] elements, @NotNull PsiElement enclosingCodeFragment) {
final List<Instruction> instructions = flow.getInstructions();
class Worker {
@NotNull
private Map<PsiVariable, IntArrayList> getWritesOffsets() {
final Map<PsiVariable, IntArrayList> writeOffsets = new THashMap<>();
for (int i = flowStart; i < flowEnd; i++) {
Instruction instruction = instructions.get(i);
if (instruction instanceof WriteVariableInstruction) {
final PsiVariable variable = ((WriteVariableInstruction) instruction).variable;
if (variable instanceof PsiLocalVariable || variable instanceof PsiParameter) {
IntArrayList offsets = writeOffsets.get(variable);
if (offsets == null)
writeOffsets.put(variable, offsets = new IntArrayList());
offsets.add(i);
}
}
}
LOG.debug("writeOffsets:", writeOffsets);
return writeOffsets;
}
@NotNull
private Map<PsiVariable, IntArrayList> getVisibleReadsOffsets(Map<PsiVariable, IntArrayList> writeOffsets, PsiCodeBlock tryBlock) {
final Map<PsiVariable, IntArrayList> visibleReadOffsets = new THashMap<>();
for (PsiVariable variable : writeOffsets.keySet()) {
if (!PsiTreeUtil.isAncestor(tryBlock, variable, true)) {
visibleReadOffsets.put(variable, new IntArrayList());
}
}
if (visibleReadOffsets.isEmpty())
return visibleReadOffsets;
for (int i = 0; i < instructions.size(); i++) {
final Instruction instruction = instructions.get(i);
if (instruction instanceof ReadVariableInstruction) {
final PsiVariable variable = ((ReadVariableInstruction) instruction).variable;
final IntArrayList readOffsets = visibleReadOffsets.get(variable);
if (readOffsets != null) {
readOffsets.add(i);
}
}
}
LOG.debug("visibleReadOffsets:", visibleReadOffsets);
return visibleReadOffsets;
}
@NotNull
private Map<PsiVariable, Set<PsiElement>> getReachableAfterWrite(Map<PsiVariable, IntArrayList> writeOffsets, Map<PsiVariable, IntArrayList> visibleReadOffsets) {
final Map<PsiVariable, Set<PsiElement>> afterWrite = new THashMap<>();
for (PsiVariable variable : visibleReadOffsets.keySet()) {
final Function<Integer, BitSet> calculator = getReachableInstructionsCalculator();
final BitSet collectedOffsets = new BitSet(flowEnd);
for (final int writeOffset : writeOffsets.get(variable).toArray()) {
LOG.assertTrue(writeOffset >= flowStart, "writeOffset");
final BitSet reachableOffsets = calculator.fun(writeOffset);
collectedOffsets.or(reachableOffsets);
}
Set<PsiElement> throwSources = afterWrite.get(variable);
if (throwSources == null)
afterWrite.put(variable, throwSources = new THashSet<>());
for (int i = flowStart; i < flowEnd; i++) {
if (collectedOffsets.get(i)) {
throwSources.add(flow.getElement(i));
}
}
final List<PsiElement> subordinates = new ArrayList<>();
for (PsiElement element : throwSources) {
if (throwSources.contains(element.getParent())) {
subordinates.add(element);
}
}
throwSources.removeAll(subordinates);
}
LOG.debug("afterWrite:", afterWrite);
return afterWrite;
}
@NotNull
private IntArrayList getCatchOrFinallyOffsets(List<PsiTryStatement> tryStatements, List<PsiClassType> thrownExceptions) {
final IntArrayList catchOrFinallyOffsets = new IntArrayList();
for (PsiTryStatement tryStatement : tryStatements) {
final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
if (finallyBlock != null) {
int offset = flow.getStartOffset(finallyBlock);
if (offset >= 0) {
// -2 is an adjustment for rethrow-after-finally
catchOrFinallyOffsets.add(offset - 2);
}
}
for (PsiCatchSection catchSection : tryStatement.getCatchSections()) {
final PsiCodeBlock catchBlock = catchSection.getCatchBlock();
final PsiParameter parameter = catchSection.getParameter();
if (catchBlock != null && parameter != null) {
for (PsiClassType throwType : thrownExceptions) {
if (isCaughtExceptionType(throwType, parameter.getType())) {
int offset = flow.getStartOffset(catchBlock);
if (offset >= 0) {
// -1 is an adjustment for catch block initialization
catchOrFinallyOffsets.add(offset - 1);
}
}
}
}
}
}
return catchOrFinallyOffsets;
}
private boolean isAnyReadOffsetReachableFrom(IntArrayList readOffsets, IntArrayList fromOffsets) {
if (readOffsets != null && !readOffsets.isEmpty()) {
final int[] readOffsetsArray = readOffsets.toArray();
for (int j = 0; j < fromOffsets.size(); j++) {
int fromOffset = fromOffsets.get(j);
if (areInstructionsReachable(flow, readOffsetsArray, fromOffset)) {
LOG.debug("reachableFromOffset:", fromOffset);
return true;
}
}
}
return false;
}
private Function<Integer, BitSet> getReachableInstructionsCalculator() {
final ControlFlowGraph graph = new ControlFlowGraph(flow.getSize()) {
@Override
void addArc(int offset, int nextOffset) {
nextOffset = promoteThroughGotoChain(flow, nextOffset);
if (nextOffset >= flowStart && nextOffset < flowEnd) {
super.addArc(offset, nextOffset);
}
}
};
graph.buildFrom(flow);
return startOffset -> {
BitSet visitedOffsets = new BitSet(flowEnd);
graph.depthFirstSearch(startOffset, visitedOffsets);
return visitedOffsets;
};
}
}
final Worker worker = new Worker();
final Map<PsiVariable, IntArrayList> writeOffsets = worker.getWritesOffsets();
if (writeOffsets.isEmpty())
return false;
final PsiElement commonParent = elements.length != 1 ? PsiTreeUtil.findCommonParent(elements) : elements[0].getParent();
final List<PsiTryStatement> tryStatements = collectTryStatementStack(commonParent, enclosingCodeFragment);
if (tryStatements.isEmpty())
return false;
final PsiCodeBlock tryBlock = tryStatements.get(0).getTryBlock();
if (tryBlock == null)
return false;
final Map<PsiVariable, IntArrayList> visibleReadOffsets = worker.getVisibleReadsOffsets(writeOffsets, tryBlock);
if (visibleReadOffsets.isEmpty())
return false;
final Map<PsiVariable, Set<PsiElement>> afterWrite = worker.getReachableAfterWrite(writeOffsets, visibleReadOffsets);
if (afterWrite.isEmpty())
return false;
for (Map.Entry<PsiVariable, Set<PsiElement>> entry : afterWrite.entrySet()) {
final PsiVariable variable = entry.getKey();
final PsiElement[] psiElements = entry.getValue().toArray(PsiElement.EMPTY_ARRAY);
final List<PsiClassType> thrownExceptions = ExceptionUtil.getThrownExceptions(psiElements);
if (!thrownExceptions.isEmpty()) {
final IntArrayList catchOrFinallyOffsets = worker.getCatchOrFinallyOffsets(tryStatements, thrownExceptions);
if (worker.isAnyReadOffsetReachableFrom(visibleReadOffsets.get(variable), catchOrFinallyOffsets)) {
return true;
}
}
}
return false;
}
use of gnu.trove.THashMap in project intellij-community by JetBrains.
the class PsiSuperMethodUtil method collectOverrideEquivalents.
@NotNull
public static Map<MethodSignature, Set<PsiMethod>> collectOverrideEquivalents(@NotNull PsiClass aClass) {
final Map<MethodSignature, Set<PsiMethod>> overrideEquivalent = new THashMap<>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
final GlobalSearchScope resolveScope = aClass.getResolveScope();
PsiClass[] supers = aClass.getSupers();
for (int i = 0; i < supers.length; i++) {
PsiClass superClass = supers[i];
boolean subType = false;
for (int j = 0; j < supers.length; j++) {
if (j == i)
continue;
subType |= supers[j].isInheritor(supers[i], true);
}
if (subType)
continue;
final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY);
for (HierarchicalMethodSignature hms : superClass.getVisibleSignatures()) {
PsiMethod method = hms.getMethod();
if (MethodSignatureUtil.findMethodBySignature(aClass, method.getSignature(superClassSubstitutor), false) != null)
continue;
final PsiClass containingClass = correctClassByScope(method.getContainingClass(), resolveScope);
if (containingClass == null)
continue;
method = containingClass.findMethodBySignature(method, false);
if (method == null)
continue;
final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, aClass, PsiSubstitutor.EMPTY);
if (containingClassSubstitutor == null)
continue;
final PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false);
final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, finalSubstitutor, false);
Set<PsiMethod> methods = overrideEquivalent.get(signature);
if (methods == null) {
methods = new LinkedHashSet<>();
overrideEquivalent.put(signature, methods);
}
methods.add(method);
}
}
return overrideEquivalent;
}
use of gnu.trove.THashMap in project intellij-community by JetBrains.
the class PropertiesGrouper method group.
@Override
@NotNull
public Collection<Group> group(@NotNull final AbstractTreeNode parent, @NotNull Collection<TreeElement> children) {
if (parent.getValue() instanceof PropertyGroup)
return Collections.emptyList();
Map<Group, Group> result = new THashMap<>();
for (TreeElement o : children) {
if (o instanceof JavaClassTreeElementBase) {
PsiElement element = ((JavaClassTreeElementBase) o).getElement();
PropertyGroup group = PropertyGroup.createOn(element, o);
if (group != null) {
PropertyGroup existing = (PropertyGroup) result.get(group);
if (existing != null) {
existing.copyAccessorsFrom(group);
} else {
result.put(group, group);
}
}
}
}
for (Iterator<Group> iterator = result.keySet().iterator(); iterator.hasNext(); ) {
PropertyGroup group = (PropertyGroup) iterator.next();
if (!group.isComplete()) {
iterator.remove();
}
}
return result.values();
}
use of gnu.trove.THashMap in project intellij-community by JetBrains.
the class SuperTypesGrouper method group.
@Override
@NotNull
public Collection<Group> group(@NotNull final AbstractTreeNode parent, @NotNull Collection<TreeElement> children) {
if (isParentGrouped(parent))
return Collections.emptyList();
Map<Group, SuperTypeGroup> groups = new THashMap<>();
for (TreeElement child : children) {
if (child instanceof PsiMethodTreeElement) {
final PsiMethodTreeElement element = (PsiMethodTreeElement) child;
PsiMethod method = ((PsiMethodTreeElement) child).getMethod();
if (element.isInherited()) {
PsiClass groupClass = method.getContainingClass();
final SuperTypeGroup group = getOrCreateGroup(groupClass, SuperTypeGroup.OwnershipType.INHERITS, groups);
group.addMethod(child);
} else {
PsiMethod[] superMethods = method.findSuperMethods();
if (superMethods.length > 0) {
//prefer interface, if there are any
for (int i = 1; i < superMethods.length; i++) {
PsiMethod superMethod = superMethods[i];
PsiClass containingClass = superMethod.getContainingClass();
if (containingClass != null && containingClass.isInterface()) {
ArrayUtil.swap(superMethods, 0, i);
break;
}
}
PsiMethod superMethod = superMethods[0];
method.putUserData(SUPER_METHOD_KEY, new WeakReference<>(superMethod));
PsiClass groupClass = superMethod.getContainingClass();
boolean overrides = methodOverridesSuper(method, superMethod);
final SuperTypeGroup.OwnershipType ownershipType = overrides ? SuperTypeGroup.OwnershipType.OVERRIDES : SuperTypeGroup.OwnershipType.IMPLEMENTS;
SuperTypeGroup group = getOrCreateGroup(groupClass, ownershipType, groups);
group.addMethod(child);
}
}
}
}
return groups.keySet();
}
Aggregations