class PropertyNameInfoImpl implements PropertyNameInfo {
  private final Class<?> sourceClass;
  private final Configuration configuration;
  private Tokens sourceClassTokens;
  private Stack<Tokens> sourcePropertyTypeTokens;
  private final Stack<Tokens> sourcePropertyTokens = new Stack<Tokens>();
  private final Stack<Tokens> destinationPropertyTokens = new Stack<Tokens>();
  private final Stack<PropertyInfo> sourceProperties = new Stack<PropertyInfo>();
  private final Stack<PropertyInfo> destinationProperties = new Stack<PropertyInfo>();

  private final Map<PropertyInfo, Tokens> sourceTypeTokensCache = new HashMap<PropertyInfo, Tokens>();
  private final Map<String, Tokens> sourceTokensCache = new HashMap<String, Tokens>();

  PropertyNameInfoImpl(Class<?> sourceClass, Configuration configuration) {
    this.sourceClass = sourceClass;
    this.configuration = configuration;
  }

  @Override
  public List<PropertyInfo> getDestinationProperties() {
    return destinationProperties;
  }

  @Override
  public List<Tokens> getDestinationPropertyTokens() {
    return destinationPropertyTokens;
  }

  @Override
  public Tokens getSourceClassTokens() {<FILL_FUNCTION_BODY>}

  @Override
  public List<PropertyInfo> getSourceProperties() {
    return sourceProperties;
  }

  @Override
  public List<Tokens> getSourcePropertyTokens() {
    return sourcePropertyTokens;
  }

  @Override
  public List<Tokens> getSourcePropertyTypeTokens() {
    if (sourcePropertyTypeTokens == null) {
      sourcePropertyTypeTokens = new Stack<Tokens>();
      for (PropertyInfo sourceProperty : sourceProperties)
        pushSourcePropertyType(sourceProperty);
    }

    return sourcePropertyTypeTokens;
  }

  @Override
  public String toString() {
    return new ToStringBuilder(PropertyNameInfoImpl.class).add("sourceProperties", sourceProperties)
        .add("destinationProperties", destinationProperties)
        .toString();
  }

  void clearSource() {
    sourceProperties.clear();
    sourcePropertyTokens.clear();
    if (sourcePropertyTypeTokens != null)
      sourcePropertyTypeTokens.clear();
  }

  void popDestination() {
    destinationProperties.pop();
    destinationPropertyTokens.pop();
  }

  void popSource() {
    sourceProperties.pop();
    sourcePropertyTokens.pop();
    if (sourcePropertyTypeTokens != null)
      sourcePropertyTypeTokens.pop();
  }

  void pushDestination(String destinationName, Mutator destinationProperty) {
    NameableType nameableType = NameableType.forPropertyType(destinationProperty.getPropertyType());
    String[] tokens = configuration.getDestinationNameTokenizer().tokenize(
        destinationName, nameableType);
    destinationPropertyTokens.push(Tokens.of(tokens));
    destinationProperties.push(destinationProperty);
  }

  void pushSource(String sourceName, Accessor sourceProperty) {
    NameableType nameableType = NameableType.forPropertyType(sourceProperty.getPropertyType());
    if (!sourceTokensCache.containsKey(sourceName)) {
      sourceTokensCache.put(sourceName, Tokens.of(configuration.getSourceNameTokenizer()
          .tokenize(sourceName, nameableType)));
    }
    sourcePropertyTokens.push(sourceTokensCache.get(sourceName));
    sourceProperties.push(sourceProperty);
    pushSourcePropertyType(sourceProperty);
  }

  private void pushSourcePropertyType(PropertyInfo sourceProperty) {
    if (sourcePropertyTypeTokens == null)
      return;
    if (!sourceTypeTokensCache.containsKey(sourceProperty)) {
      String typeName = configuration.getSourceNameTransformer().transform(
          sourceProperty.getType().getSimpleName(), NameableType.CLASS);
      sourceTypeTokensCache.put(sourceProperty, Tokens.of(configuration.getSourceNameTokenizer()
          .tokenize(typeName, NameableType.CLASS)));
    }
    sourcePropertyTypeTokens.add(sourceTypeTokensCache.get(sourceProperty));
  }
}

    if (sourceClassTokens == null) {
      String className = configuration.getSourceNameTransformer().transform(
          sourceClass.getSimpleName(), NameableType.CLASS);
      sourceClassTokens = Tokens.of(configuration.getSourceNameTokenizer().tokenize(className,
          NameableType.CLASS));
    }

    return sourceClassTokens;
  
<no_super_class>