/**
   * @param binding must be correspond to a type, method or field declaration.
   * @return the compilation unit that contains the declaration of the given binding.
   */
  public CompilationUnit getCompilationUnitForBinding(final IBinding binding) {
    assert binding.getKind() == IBinding.TYPE
        || binding.getKind() == IBinding.METHOD
        || binding.getKind() == IBinding.VARIABLE;
    CompilationUnit domUnit = searchLocallyForBinding(binding);
    if (domUnit != null) return domUnit;
    else {
      final IMember member = (IMember) binding.getJavaElement();
      final ICompilationUnit unit;
      if (member != null) {
        unit = member.getCompilationUnit();
      } else {
        final ITypeBinding typeBinding = getDeclaringClass(binding);
        // binary type don't have compilation unit.
        if (!typeBinding.isFromSource()) return null;
        if (_typeBinding2ModelCompUnit.get(typeBinding) != null)
          unit = _typeBinding2ModelCompUnit.get(typeBinding);
        else {
          final String qname = typeBinding.getQualifiedName();
          unit = getICompilationUnitForTopLevelType(qname);
        }
      }
      if (unit == null) return null;

      final CompilationUnit astUnit = _modelCompUnit2astCompUnit.get(unit);
      if (astUnit != null) return astUnit;
      else {
        // Note: very expensive operation. we are re-compiling a file with binding information.
        final ASTParser parser = ASTParser.newParser(AST.JLS3);
        parser.setResolveBindings(true);
        parser.setBindingsRecovery(true);
        parser.setSource(unit);
        parser.setFocalPosition(0);
        parser.setIgnoreMethodBodies(true);
        CompilationUnit resultUnit = (CompilationUnit) parser.createAST(null);
        _modelCompUnit2astCompUnit.put(unit, resultUnit);
        return resultUnit;
      }
    }
  }