private void analyzeDfaWithNestedClosures( PsiElement scope, ProblemsHolder holder, StandardDataFlowRunner dfaRunner, Collection<DfaMemoryState> initialStates) { final DataFlowInstructionVisitor visitor = new DataFlowInstructionVisitor(dfaRunner); final RunnerResult rc = dfaRunner.analyzeMethod(scope, visitor, IGNORE_ASSERT_STATEMENTS, initialStates); if (rc == RunnerResult.OK) { createDescription(dfaRunner, holder, visitor); MultiMap<PsiElement, DfaMemoryState> nestedClosures = dfaRunner.getNestedClosures(); for (PsiElement closure : nestedClosures.keySet()) { analyzeDfaWithNestedClosures(closure, holder, dfaRunner, nestedClosures.get(closure)); } } else if (rc == RunnerResult.TOO_COMPLEX) { if (scope.getParent() instanceof PsiMethod) { PsiMethod method = (PsiMethod) scope.getParent(); final PsiIdentifier name = method.getNameIdentifier(); if (name != null) { // Might be null for synthetic methods like JSP page. holder.registerProblem( name, InspectionsBundle.message("dataflow.too.complex"), ProblemHighlightType.WEAK_WARNING); } } } }
@Override public void visitMethod(@NotNull PsiMethod method) { super.visitMethod(method); final PsiCodeBlock body = method.getBody(); if (body == null) { return; } if (method.getNameIdentifier() == null) { return; } final PsiMethod leastConcreteSuperMethod = getLeastConcreteSuperMethod(method); if (leastConcreteSuperMethod == null) { return; } final PsiClass objectClass = ClassUtils.findObjectClass(method); final PsiMethod[] superMethods = method.findSuperMethods(objectClass); if (superMethods.length > 0) { return; } if (ignoreEmptySuperMethods) { final PsiMethod superMethod = (PsiMethod) leastConcreteSuperMethod.getNavigationElement(); if (MethodUtils.isTrivial(superMethod, true)) { return; } } if (onlyReportWhenAnnotated) { if (!AnnotationUtil.isAnnotated(leastConcreteSuperMethod, annotations)) { return; } } if (containsSuperCall(body, leastConcreteSuperMethod)) { return; } registerMethodError(method); }
@Override public void visitMethod(@NotNull PsiMethod method) { // note: no call to super if (method.getNameIdentifier() == null) { return; } if (!method.isConstructor()) { return; } if (ignoreScope != Scope.NONE) { switch (ignoreScope.ordinal()) { case 3: if (method.hasModifierProperty(PsiModifier.PROTECTED)) return; case 2: if (method.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) return; case 1: if (method.hasModifierProperty(PsiModifier.PRIVATE)) return; } } final PsiParameterList parameterList = method.getParameterList(); final int parametersCount = parameterList.getParametersCount(); if (parametersCount <= getLimit()) { return; } registerMethodError(method, Integer.valueOf(parametersCount)); }
protected final void registerMethodError(@NotNull PsiMethod method, Object... infos) { final PsiElement nameIdentifier = method.getNameIdentifier(); if (nameIdentifier == null) { registerError(method.getContainingFile(), infos); } else { registerError(nameIdentifier, infos); } }
/** * Check the element. If the element is a PsiMethod, than we want to know if it's a @Provides * method, or a Constructor annotated w/ @Inject. * * <p>If element is a field, than we only want to see if it is annotated with @Inject. * * @return a {@link com.intellij.codeInsight.daemon.GutterIconNavigationHandler} for the * appropriate type, or null if we don't care about it. */ @Nullable @Override public LineMarkerInfo getLineMarkerInfo(@NotNull final PsiElement element) { // Check methods first (includes constructors). if (element instanceof PsiMethod) { PsiMethod methodElement = (PsiMethod) element; // @Provides if (PsiConsultantImpl.hasAnnotation(element, CLASS_PROVIDES)) { PsiTypeElement returnTypeElement = methodElement.getReturnTypeElement(); if (returnTypeElement != null) { return new LineMarkerInfo<PsiElement>( element, returnTypeElement.getTextRange(), ICON, UPDATE_ALL, null, new ProvidesToInjectHandler(), LEFT); } } // Constructor injection. if (methodElement.isConstructor() && PsiConsultantImpl.hasAnnotation(element, CLASS_INJECT)) { PsiIdentifier nameIdentifier = methodElement.getNameIdentifier(); if (nameIdentifier != null) { return new LineMarkerInfo<PsiElement>( element, nameIdentifier.getTextRange(), ICON, UPDATE_ALL, null, new ConstructorInjectToProvidesHandler(), LEFT); } } // Not a method, is it a Field? } else if (element instanceof PsiField) { // Field injection. PsiField fieldElement = (PsiField) element; PsiTypeElement typeElement = fieldElement.getTypeElement(); if (PsiConsultantImpl.hasAnnotation(element, CLASS_INJECT) && typeElement != null) { return new LineMarkerInfo<PsiElement>( element, typeElement.getTextRange(), ICON, UPDATE_ALL, null, new FieldInjectToProvidesHandler(), LEFT); } } return null; }
@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) { final Collection<RefElement> inReferences = refMethod.getInReferences(); if (inReferences.size() == 1) { final RefElement refElement = inReferences.iterator().next(); final PsiElement usagesContainer = refElement.getElement(); if (usagesContainer == null) return null; if (ReferencesSearch.search(psiMethod, new LocalSearchScope(usagesContainer)) .forEach( new Processor<PsiReference>() { private final Set<PsiReference> myFoundRefs = new HashSet<>(); @Override public boolean process(PsiReference reference) { myFoundRefs.add(reference); return myFoundRefs.size() < 2; } })) return 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 public void visitMethod(@NotNull PsiMethod method) { super.visitMethod(method); if (method.isConstructor() || method.hasModifierProperty(PsiModifier.STATIC)) { return; } if (method.hasModifierProperty(PsiModifier.NATIVE) && isInspectionEnabled("NativeMethodNamingConvention", method)) { return; } final PsiIdentifier nameIdentifier = method.getNameIdentifier(); if (nameIdentifier == null) { return; } if (TestUtils.isRunnable(method)) { if (TestUtils.isJUnit4TestMethod(method) && isInspectionEnabled("JUnit4MethodNamingConvention", method)) { return; } if (TestUtils.isJUnit3TestMethod(method) && isInspectionEnabled("JUnit3MethodNamingConvention", method)) { return; } } if (isTestNGTestMethod(method) && isInspectionEnabled("TestNGMethodNamingConvention", method)) { return; } final String name = method.getName(); if (isValid(name)) { return; } if (!isOnTheFly() && MethodUtils.hasSuper(method)) { return; } if (LibraryUtil.isOverrideOfLibraryMethod(method)) { return; } registerMethodError(method, name); }
private static void processPrimaryMethod( JavaChangeInfo changeInfo, PsiMethod method, PsiMethod baseMethod, boolean isOriginal) throws IncorrectOperationException { PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); if (changeInfo.isVisibilityChanged()) { PsiModifierList modifierList = method.getModifierList(); final String highestVisibility = isOriginal ? changeInfo.getNewVisibility() : VisibilityUtil.getHighestVisibility( changeInfo.getNewVisibility(), VisibilityUtil.getVisibilityModifier(modifierList)); VisibilityUtil.setVisibility(modifierList, highestVisibility); } if (changeInfo.isNameChanged()) { String newName = baseMethod == null ? changeInfo.getNewName() : RefactoringUtil.suggestNewOverriderName( method.getName(), baseMethod.getName(), changeInfo.getNewName()); if (newName != null && !newName.equals(method.getName())) { final PsiIdentifier nameId = method.getNameIdentifier(); assert nameId != null; nameId.replace( JavaPsiFacade.getInstance(method.getProject()) .getElementFactory() .createIdentifier(newName)); } } final PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : ChangeSignatureProcessor.calculateSubstitutor(method, baseMethod); if (changeInfo.isReturnTypeChanged()) { PsiType newTypeElement = changeInfo .getNewReturnType() .getType(changeInfo.getMethod().getParameterList(), method.getManager()); final PsiType returnType = substitutor.substitute(newTypeElement); // don't modify return type for non-Java overriders (EJB) if (method.getName().equals(changeInfo.getNewName())) { final PsiTypeElement typeElement = method.getReturnTypeElement(); if (typeElement != null) { typeElement.replace(factory.createTypeElement(returnType)); } } } PsiParameterList list = method.getParameterList(); PsiParameter[] parameters = list.getParameters(); final JavaParameterInfo[] parameterInfos = changeInfo.getNewParameters(); final int delta = baseMethod != null ? baseMethod.getParameterList().getParametersCount() - method.getParameterList().getParametersCount() : 0; PsiParameter[] newParms = new PsiParameter[Math.max(parameterInfos.length - delta, 0)]; final String[] oldParameterNames = changeInfo.getOldParameterNames(); final String[] oldParameterTypes = changeInfo.getOldParameterTypes(); for (int i = 0; i < newParms.length; i++) { JavaParameterInfo info = parameterInfos[i]; int index = info.getOldIndex(); if (index >= 0) { PsiParameter parameter = parameters[index]; newParms[i] = parameter; String oldName = oldParameterNames[index]; if (!oldName.equals(info.getName()) && oldName.equals(parameter.getName())) { PsiIdentifier newIdentifier = factory.createIdentifier(info.getName()); parameter.getNameIdentifier().replace(newIdentifier); } String oldType = oldParameterTypes[index]; if (!oldType.equals(info.getTypeText())) { parameter.normalizeDeclaration(); PsiType newType = substitutor.substitute( info.createType(changeInfo.getMethod().getParameterList(), method.getManager())); parameter.getTypeElement().replace(factory.createTypeElement(newType)); } } else { newParms[i] = createNewParameter(changeInfo, info, substitutor); } } resolveParameterVsFieldsConflicts(newParms, method, list, changeInfo.toRemoveParm()); fixJavadocsForChangedMethod(method, changeInfo, newParms.length); if (changeInfo.isExceptionSetOrOrderChanged()) { final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(changeInfo); fixPrimaryThrowsLists(method, newExceptions); } }
@Override public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { if (!MinecraftSettings.Companion.getInstance().isShowEventListenerGutterIcons()) { return; } // Since we want to line up with the method declaration, not the annotation // declaration, we need to target identifiers, not just PsiMethods. if (!(element instanceof PsiIdentifier && (element.getParent() instanceof PsiMethod))) { return; } // The PsiIdentifier is going to be a method of course! PsiMethod method = (PsiMethod) element.getParent(); if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { // I don't think any implementation allows for abstract return; } PsiModifierList modifierList = method.getModifierList(); Module module = ModuleUtilCore.findModuleForPsiElement(element); if (module == null) { return; } MinecraftModule instance = MinecraftModule.getInstance(module); if (instance == null) { return; } // Since each platform has their own valid listener annotations, // some platforms may have multiple allowed annotations for various cases final Collection<AbstractModuleType<?>> moduleTypes = instance.getTypes(); boolean contains = false; for (AbstractModuleType<?> moduleType : moduleTypes) { final List<String> listenerAnnotations = moduleType.getListenerAnnotations(); for (String listenerAnnotation : listenerAnnotations) { if (modifierList.findAnnotation(listenerAnnotation) != null) { contains = true; break; } } } if (!contains) { return; } final PsiParameter[] parameters = method.getParameterList().getParameters(); if (parameters.length < 1) { return; } final PsiParameter eventParameter = parameters[0]; if (eventParameter == null) { // Listeners must have at least a single parameter return; } // Get the type of the parameter so we can start resolving it PsiTypeElement psiEventElement = eventParameter.getTypeElement(); if (psiEventElement == null) { return; } final PsiType type = psiEventElement.getType(); // Validate that it is a class reference type, I don't know if this will work with // other JVM languages such as Kotlin or Scala, but it might! if (!(type instanceof PsiClassReferenceType)) { return; } // And again, make sure that we can at least resolve the type, otherwise it's not a valid // class reference. final PsiClass eventClass = ((PsiClassReferenceType) type).resolve(); if (eventClass == null) { return; } if (instance.isEventClassValid(eventClass, method)) { return; } if (!instance.isStaticListenerSupported(eventClass, method) && method.hasModifierProperty(PsiModifier.STATIC)) { if (method.getNameIdentifier() != null) { holder.createErrorAnnotation( method.getNameIdentifier(), "Event listener method must not be static"); } } if (!isSuperEventListenerAllowed(eventClass, method, instance)) { holder.createErrorAnnotation( eventParameter, instance.writeErrorMessageForEvent(eventClass, method)); } }