void (@NotNull CompletionParameters parameters, @NotNull ProcessingContext context, @NotNull CompletionResultSet result) { PsiFile file = parameters.getOriginalFile(); if (!(file instanceof GroovyFile groovyFile)) return; if (!groovyFile.isScript()) return; GrReferenceExpression ref = (GrReferenceExpression)parameters.getPosition().getParent(); if (ref == null) return; final Map<String, Boolean> variants = new HashMap<>(); collectVariants((s, isFinal) -> variants.put(s, isFinal), ref, groovyFile); if (variants.isEmpty()) return; // Remove existing variants. PsiElement parent = ref.getParent(); if (parent instanceof GrAssignmentExpression) { parent = parent.getParent(); } if (parent == null) return; Set<String> processedPrefixes = new HashSet<>(); Set<String> prefixesInMethodCall = new HashSet<>(); for (PsiElement e = parent.getFirstChild(); e != null; e = e.getNextSibling()) { if (e instanceof GrAssignmentExpression) { PsiElement left = ((GrAssignmentExpression)e).getLValue(); if (left instanceof GrReferenceExpression) { String s = refToString((GrReferenceExpression)left); if (s == null) continue; int dotIndex = s.indexOf('.'); if (dotIndex > 0) { processedPrefixes.add(s.substring(0, dotIndex)); } variants.remove(s); } } else if (e instanceof GrMethodCall call) { if (isPropertyCall(call)) { String name = extractPropertyName(call); if (name == null) continue; processedPrefixes.add(name); prefixesInMethodCall.add(name); variants.remove(name); } } } // Process variants. for (Map.Entry<String, Boolean> entry : variants.entrySet()) { String variant = entry.getKey(); int dotIndex = variant.indexOf('.'); if (dotIndex > 0 && dotIndex < variant.length() - 1) { String p = variant.substring(0, dotIndex); if (prefixesInMethodCall.contains(p)) continue; if (myAddPrefixes && processedPrefixes.add(p)) { result.addElement(LookupElementBuilder.create(p)); } } LookupElement lookupElement = LookupElementBuilder.create(variant); if (entry.getValue()) { lookupElement = TailTypeDecorator.withTail(lookupElement, EqTailType.INSTANCE); } result.addElement(lookupElement); } }