code: private Function renameVariables(Function function, ImmutableMap<QualifiedAttributeID, Term> attributes,
                                              QuotedIDFactory idfac) throws AttributeNotFoundException {
          List<Term> terms = function.getTerms();
          List<Term> newTerms = new ArrayList<>(terms.size());
  
          for (Term term : terms) {
              Term newTerm;
              if (term instanceof Variable) {
                  Variable var = (Variable) term;
                  QuotedID attribute = idfac.createAttributeID(var.getName());
                  newTerm = attributes.get(new QualifiedAttributeID(null, attribute));
  
                  if (newTerm == null) {
                      QuotedID quotedAttribute = QuotedID.createIdFromDatabaseRecord(idfac, var.getName());
                      newTerm = attributes.get(new QualifiedAttributeID(null, quotedAttribute));
  
                      if (newTerm == null)
                          throw new AttributeNotFoundException("The source query does not provide the attribute " + attribute
                                  + " (variable " + var.getName() + ") required by the target atom.");
                  }
              }
              else if (term instanceof Function)
                  newTerm = renameVariables((Function) term, attributes, idfac);
              else if (term instanceof Constant)
                  newTerm = term.clone();
              else
                  throw new RuntimeException("Unknown term type: " + term);
  
              newTerms.add(newTerm);
          }
  
          return termFactory.getFunction(function.getFunctionSymbol(), newTerms);
      }
docs: Returns a new function by renaming variables occurring in the {@code function}
  according to the {@code attributes} lookup table