public static MultiMap<PsiElement, UsageInfo> classifyUsages( Collection<? extends PsiElement> elements, UsageInfo[] usages) { final MultiMap<PsiElement, UsageInfo> result = new MultiMap<PsiElement, UsageInfo>(); for (UsageInfo usage : usages) { LOG.assertTrue(usage instanceof MoveRenameUsageInfo); if (usage.getReference() instanceof LightElement) { continue; // filter out implicit references (e.g. from derived class to super class' default // constructor) } MoveRenameUsageInfo usageInfo = (MoveRenameUsageInfo) usage; if (usage instanceof RelatedUsageInfo) { final PsiElement relatedElement = ((RelatedUsageInfo) usage).getRelatedElement(); if (elements.contains(relatedElement)) { result.putValue(relatedElement, usage); } } else { PsiElement referenced = usageInfo.getReferencedElement(); if (elements.contains(referenced)) { result.putValue(referenced, usage); } else if (referenced != null) { PsiElement indirect = referenced.getNavigationElement(); if (elements.contains(indirect)) { result.putValue(indirect, usage); } } } } return result; }
public Collection<PsiElement> getAdditionalElementsToDelete( @NotNull final PsiElement element, @NotNull final Collection<PsiElement> allElementsToDelete, final boolean askUser) { if (element instanceof PsiField) { PsiField field = (PsiField) element; final Project project = element.getProject(); String propertyName = JavaCodeStyleManager.getInstance(project) .variableNameToPropertyName(field.getName(), VariableKind.FIELD); PsiClass aClass = field.getContainingClass(); if (aClass != null) { boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); PsiMethod[] getters = GetterSetterPrototypeProvider.findGetters(aClass, propertyName, isStatic); if (getters != null) { final List<PsiMethod> validGetters = new ArrayList<>(1); for (PsiMethod getter : getters) { if (!allElementsToDelete.contains(getter) && (getter != null && getter.isPhysical())) { validGetters.add(getter); } } getters = validGetters.isEmpty() ? null : validGetters.toArray(new PsiMethod[validGetters.size()]); } PsiMethod setter = PropertyUtil.findPropertySetter(aClass, propertyName, isStatic, false); if (allElementsToDelete.contains(setter) || setter != null && !setter.isPhysical()) setter = null; if (askUser && (getters != null || setter != null)) { final String message = RefactoringMessageUtil.getGetterSetterMessage( field.getName(), RefactoringBundle.message("delete.title"), getters != null ? getters[0] : null, setter); if (!ApplicationManager.getApplication().isUnitTestMode() && Messages.showYesNoDialog( project, message, RefactoringBundle.message("safe.delete.title"), Messages.getQuestionIcon()) != Messages.YES) { getters = null; setter = null; } } List<PsiElement> elements = new ArrayList<>(); if (setter != null) elements.add(setter); if (getters != null) Collections.addAll(elements, getters); return elements; } } return null; }
private static void addAllIfNotPresent(Collection<String> collection, String... annotations) { for (String annotation : annotations) { LOG.assertTrue(annotation != null); if (!collection.contains(annotation)) { collection.add(annotation); } } }
public static boolean isMethodParameterAnnotatedWith( final PsiMethod method, final int idx, @Nullable Collection<PsiMethod> processed, final String annFqn, @Nullable Map<String, Object> annotationAttributeValues, @Nullable final Set<PsiModifierListOwner> nonNlsTargets) { if (processed != null) { if (processed.contains(method)) return false; } else { processed = new THashSet<PsiMethod>(); } processed.add(method); final PsiParameter[] params = method.getParameterList().getParameters(); PsiParameter param; if (idx >= params.length) { if (params.length == 0) { return false; } PsiParameter lastParam = params[params.length - 1]; if (lastParam.isVarArgs()) { param = lastParam; } else { return false; } } else { param = params[idx]; } final PsiAnnotation annotation = AnnotationUtil.findAnnotation(param, annFqn); if (annotation != null) { return processAnnotationAttributes(annotationAttributeValues, annotation); } if (nonNlsTargets != null) { nonNlsTargets.add(param); } final PsiMethod[] superMethods = method.findSuperMethods(); for (PsiMethod superMethod : superMethods) { if (isMethodParameterAnnotatedWith( superMethod, idx, processed, annFqn, annotationAttributeValues, null)) return true; } return false; }
public CommonProblemDescriptor[] checkElement( @NotNull final PsiElement psiElement, InspectionManager manager, Project project) { final Map<PsiElement, Collection<String>> suppressedScopes = new THashMap<PsiElement, Collection<String>>(); 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 = SuppressManager.getInstance().getSuppressedInspectionIdsIn(owner); if (idsString != null && idsString.length() != 0) { 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 null; // have to visit all file from scratch since inspections can be written in any perversive way // including checkFile() overriding Collection<InspectionTool> suppressedTools = new THashSet<InspectionTool>(); InspectionTool[] tools = getInspectionTools(psiElement, manager); for (Collection<String> ids : suppressedScopes.values()) { for (Iterator<String> iterator = ids.iterator(); iterator.hasNext(); ) { final String shortName = iterator.next().trim(); for (InspectionTool tool : tools) { if (tool instanceof LocalInspectionToolWrapper && ((LocalInspectionToolWrapper) tool).getTool().getID().equals(shortName)) { if (!((LocalInspectionToolWrapper) tool).isUnfair()) { suppressedTools.add(tool); } else { iterator.remove(); break; } } else if (tool.getShortName().equals(shortName)) { // ignore global unused as it won't be checked anyway if (!(tool instanceof LocalInspectionToolWrapper) && !(tool instanceof GlobalInspectionToolWrapper)) { iterator.remove(); break; } else { suppressedTools.add(tool); } } } } } final AnalysisScope scope = new AnalysisScope(psiElement.getContainingFile()); final InspectionManagerEx inspectionManagerEx = ((InspectionManagerEx) InspectionManager.getInstance(project)); GlobalInspectionContextImpl globalContext = inspectionManagerEx.createNewGlobalContext(false); globalContext.setCurrentScope(scope); final RefManagerImpl refManager = ((RefManagerImpl) globalContext.getRefManager()); refManager.inspectionReadActionStarted(); final List<ProblemDescriptor> result; try { result = new ArrayList<ProblemDescriptor>(); for (InspectionTool tool : suppressedTools) { String toolId = tool instanceof LocalInspectionToolWrapper ? ((LocalInspectionToolWrapper) tool).getTool().getID() : tool.getShortName(); tool.initialize(globalContext); Collection<CommonProblemDescriptor> descriptors; if (tool instanceof LocalInspectionToolWrapper) { LocalInspectionToolWrapper local = (LocalInspectionToolWrapper) tool; if (local.isUnfair()) continue; // cant't work with passes other than LocalInspectionPass local.processFile(psiElement.getContainingFile(), false, manager); descriptors = local.getProblemDescriptors(); } else if (tool instanceof GlobalInspectionToolWrapper) { GlobalInspectionToolWrapper global = (GlobalInspectionToolWrapper) tool; if (global.getTool().isGraphNeeded()) { refManager.findAllDeclarations(); } global.processFile(scope, manager, globalContext, false); descriptors = global.getProblemDescriptors(); } 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 = SuppressManager.getInstance().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) { PsiMember psiMember; String problemLine = null; if (suppressedScope instanceof PsiMember) { psiMember = (PsiMember) suppressedScope; } else { psiMember = PsiTreeUtil.getParentOfType(suppressedScope, PsiDocCommentOwner.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<String, QuickFix>(); 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 = null; if (psiMember instanceof PsiMethod) { identifier = ((PsiMethod) psiMember).getNameIdentifier(); } else if (psiMember instanceof PsiField) { identifier = ((PsiField) psiMember).getNameIdentifier(); } else if (psiMember instanceof PsiClass) { identifier = ((PsiClass) 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()]); }
@NotNull final RunnerResult analyzeMethod( @NotNull PsiElement psiBlock, @NotNull InstructionVisitor visitor, boolean ignoreAssertions, @NotNull Collection<DfaMemoryState> initialStates) { if (PsiTreeUtil.findChildOfType(psiBlock, OuterLanguageElement.class) != null) return RunnerResult.NOT_APPLICABLE; try { final ControlFlow flow = new ControlFlowAnalyzer(myValueFactory, psiBlock, ignoreAssertions).buildControlFlow(); if (flow == null) return RunnerResult.NOT_APPLICABLE; int[] loopNumber = LoopAnalyzer.calcInLoop(flow); int endOffset = flow.getInstructionCount(); myInstructions = flow.getInstructions(); myNestedClosures.clear(); Set<Instruction> joinInstructions = ContainerUtil.newHashSet(); for (int index = 0; index < myInstructions.length; index++) { Instruction instruction = myInstructions[index]; if (instruction instanceof GotoInstruction) { joinInstructions.add(myInstructions[((GotoInstruction) instruction).getOffset()]); } else if (instruction instanceof ConditionalGotoInstruction) { joinInstructions.add( myInstructions[((ConditionalGotoInstruction) instruction).getOffset()]); } else if (instruction instanceof MethodCallInstruction && !((MethodCallInstruction) instruction).getContracts().isEmpty()) { joinInstructions.add(myInstructions[index + 1]); } } if (LOG.isDebugEnabled()) { LOG.debug("Analyzing code block: " + psiBlock.getText()); for (int i = 0; i < myInstructions.length; i++) { LOG.debug(i + ": " + myInstructions[i]); } } // for (int i = 0; i < myInstructions.length; i++) System.out.println(i + ": " + // myInstructions[i].toString()); Integer tooExpensiveHash = psiBlock.getUserData(TOO_EXPENSIVE_HASH); if (tooExpensiveHash != null && tooExpensiveHash == psiBlock.getText().hashCode()) { LOG.debug("Too complex because hasn't changed since being too complex already"); return RunnerResult.TOO_COMPLEX; } final StateQueue queue = new StateQueue(); for (final DfaMemoryState initialState : initialStates) { queue.offer(new DfaInstructionState(myInstructions[0], initialState)); } MultiMap<BranchingInstruction, DfaMemoryState> processedStates = MultiMap.createSet(); MultiMap<BranchingInstruction, DfaMemoryState> incomingStates = MultiMap.createSet(); long msLimit = shouldCheckTimeLimit() ? Registry.intValue("ide.dfa.time.limit.online") : Registry.intValue("ide.dfa.time.limit.offline"); WorkingTimeMeasurer measurer = new WorkingTimeMeasurer(msLimit * 1000 * 1000); int count = 0; while (!queue.isEmpty()) { List<DfaInstructionState> states = queue.getNextInstructionStates(joinInstructions); for (DfaInstructionState instructionState : states) { if (count++ % 1024 == 0 && measurer.isTimeOver()) { LOG.debug("Too complex because the analysis took too long"); psiBlock.putUserData(TOO_EXPENSIVE_HASH, psiBlock.getText().hashCode()); return RunnerResult.TOO_COMPLEX; } ProgressManager.checkCanceled(); if (LOG.isDebugEnabled()) { LOG.debug(instructionState.toString()); } // System.out.println(instructionState.toString()); Instruction instruction = instructionState.getInstruction(); if (instruction instanceof BranchingInstruction) { BranchingInstruction branching = (BranchingInstruction) instruction; Collection<DfaMemoryState> processed = processedStates.get(branching); if (processed.contains(instructionState.getMemoryState())) { continue; } if (processed.size() > MAX_STATES_PER_BRANCH) { LOG.debug("Too complex because too many different possible states"); return RunnerResult.TOO_COMPLEX; // Too complex :( } if (loopNumber[branching.getIndex()] != 0) { processedStates.putValue(branching, instructionState.getMemoryState().createCopy()); } } DfaInstructionState[] after = acceptInstruction(visitor, instructionState); for (DfaInstructionState state : after) { Instruction nextInstruction = state.getInstruction(); if (nextInstruction.getIndex() >= endOffset) { continue; } handleStepOutOfLoop( instruction, nextInstruction, loopNumber, processedStates, incomingStates, states, after, queue); if (nextInstruction instanceof BranchingInstruction) { BranchingInstruction branching = (BranchingInstruction) nextInstruction; if (processedStates.get(branching).contains(state.getMemoryState()) || incomingStates.get(branching).contains(state.getMemoryState())) { continue; } if (loopNumber[branching.getIndex()] != 0) { incomingStates.putValue(branching, state.getMemoryState().createCopy()); } } queue.offer(state); } } } psiBlock.putUserData(TOO_EXPENSIVE_HASH, null); LOG.debug("Analysis ok"); return RunnerResult.OK; } catch (ArrayIndexOutOfBoundsException e) { LOG.error(psiBlock.getText(), e); return RunnerResult.ABORTED; } catch (EmptyStackException e) { LOG.error(psiBlock.getText(), e); return RunnerResult.ABORTED; } }