@NotNull public static List<StandardMethodContract> inferContracts(@NotNull PsiMethodImpl method) { if(!InferenceFromSourceUtil.shouldInferFromSource(method)) { return Collections.emptyList(); } return CachedValuesManager.getCachedValue(method, () -> { MethodData data = ContractInferenceIndexKt.getIndexedData(method); List<PreContract> preContracts = data == null ? Collections.emptyList() : data.getContracts(); List<StandardMethodContract> result = RecursionManager.doPreventingRecursion(method, true, () -> postProcessContracts(method, data, preContracts)); if(result == null) { result = Collections.emptyList(); } return CachedValueProvider.Result.create(result, method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); }); }
@NotNull private static List<StandardMethodContract> postProcessContracts(@NotNull PsiMethodImpl method, MethodData data, List<PreContract> rawContracts) { List<StandardMethodContract> contracts = ContainerUtil.concat(rawContracts, c -> c.toContracts(method, data.methodBody(method))); if(contracts.isEmpty()) { return Collections.emptyList(); } final PsiType returnType = method.getReturnType(); if(returnType != null && !(returnType instanceof PsiPrimitiveType)) { contracts = boxReturnValues(contracts); } List<StandardMethodContract> compatible = ContainerUtil.filter(contracts, contract -> isContractCompatibleWithMethod(method, returnType, contract)); if(compatible.size() > MAX_CONTRACT_COUNT) { LOG.debug("Too many contracts for " + PsiUtil.getMemberQualifiedName(method) + ", shrinking the list"); return compatible.subList(0, MAX_CONTRACT_COUNT); } return compatible; }
public static Nullness inferNullity(PsiMethodImpl method) { if(!InferenceFromSourceUtil.shouldInferFromSource(method)) { return Nullness.UNKNOWN; } PsiType type = method.getReturnType(); if(type == null || type instanceof PsiPrimitiveType) { return Nullness.UNKNOWN; } return CachedValuesManager.getCachedValue(method, () -> { MethodData data = ContractInferenceIndexKt.getIndexedData(method); NullityInferenceResult result = data == null ? null : data.getNullity(); Nullness nullness = result == null ? null : RecursionManager.doPreventingRecursion(method, true, () -> result.getNullness(method, data.methodBody(method))); if(nullness == null) { nullness = Nullness.UNKNOWN; } return CachedValueProvider.Result.create(nullness, method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); }); }
@Nullable private PsiAnnotation getInferredNullityAnnotation(PsiMethodImpl method) { NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject); if(AnnotationUtil.findAnnotation(method, manager.getNotNulls(), true) != null || AnnotationUtil.findAnnotation(method, manager.getNullables(), true) != null) { return null; } if(NullableNotNullManager.findNullabilityDefaultInHierarchy(method, true) != null || NullableNotNullManager.findNullabilityDefaultInHierarchy(method, false) != null) { return null; } Nullness nullness = NullityInference.inferNullity(method); if(nullness == Nullness.NOT_NULL) { return ProjectBytecodeAnalysis.getInstance(myProject).getNotNullAnnotation(); } if(nullness == Nullness.NULLABLE) { return ProjectBytecodeAnalysis.getInstance(myProject).getNullableAnnotation(); } return null; }
@Override public PsiMethod createPsi(@NotNull final ASTNode node) { if (node instanceof AnnotationMethodElement) { return new PsiAnnotationMethodImpl(node); } else { return new PsiMethodImpl(node); } }
@NotNull public List<PsiElement> getPsiElements(StepCollector collector, PsiElement element) { List<PsiElement> elements = new ArrayList<>(); if (element instanceof ConceptStepImpl) elements = collector.get(getConceptStepText((ConceptStepImpl) element)); else if (element instanceof PsiMethodImpl) for (String alias : StepUtil.getGaugeStepAnnotationValues((PsiMethod) element)) elements.addAll(collector.get(getStepText(alias, element))); else if (element instanceof SpecStepImpl) { elements = collector.get(getStepText((SpecStepImpl) element)); elements.addAll(collector.get(((SpecStepImpl) element).getName())); } return elements; }
@Override public PsiMethod createPsi(@NotNull final ASTNode node) { if(node instanceof AnnotationMethodElement) { return new PsiAnnotationMethodImpl(node); } else { return new PsiMethodImpl(node); } }
public static boolean inferPurity(@NotNull PsiMethodImpl method) { if(!InferenceFromSourceUtil.shouldInferFromSource(method) || PsiType.VOID.equals(method.getReturnType()) || method.isConstructor()) { return false; } return CachedValuesManager.getCachedValue(method, () -> { MethodData data = ContractInferenceIndexKt.getIndexedData(method); PurityInferenceResult result = data == null ? null : data.getPurity(); Boolean pure = RecursionManager.doPreventingRecursion(method, true, () -> result != null && result.isPure(method, data.methodBody(method))); return CachedValueProvider.Result.create(pure == Boolean.TRUE, method); }); }
public Supplier<PsiCodeBlock> methodBody(PsiMethodImpl method) { return () -> { PsiMethodStub stub = method.getStub(); if(stub != null) { return CachedValuesManager.getCachedValue(method, () -> new CachedValueProvider.Result<>(getDetachedBody(method), method)); } else { return method.getBody(); } }; }
@Nullable private PsiAnnotation getInferredContractAnnotation(PsiMethodImpl method) { if(method.getModifierList().findAnnotation(ORG_JETBRAINS_ANNOTATIONS_CONTRACT) != null) { return null; } return createContractAnnotation(ContractInference.inferContracts(method), PurityInference.inferPurity(method)); }
static boolean shouldInferFromSource(@NotNull PsiMethodImpl method) { return CachedValuesManager.getCachedValue(method, () -> CachedValueProvider.Result.create(calcShouldInferFromSource(method), method, PsiModificationTracker .JAVA_STRUCTURE_MODIFICATION_COUNT)); }
public static MethodData getIndexedData(PsiMethodImpl method) { Map<Integer, MethodData> map = ourMethodDataPsiFileGist.getFileData(method.getContainingFile()); return map == null ? null : map.get(methodIndex(method)); }