void ReduceClassTemplateParameter::removeOneParameterFromPartialDecl(
       const ClassTemplatePartialSpecializationDecl *PartialD,
       const TemplateArgument &Arg)
{
  if (!Arg.isInstantiationDependent())
    return;

  TemplateArgument::ArgKind K = Arg.getKind();
  switch (K) {
  case TemplateArgument::Expression:
    removeOneParameterByArgExpression(PartialD, Arg);
    return;

  case TemplateArgument::Template:
    removeOneParameterByArgTemplate(PartialD, Arg);
    return;

  case TemplateArgument::Type:
    removeOneParameterByArgType(PartialD, Arg);
    return;
  
  default:
    TransAssert(0 && "Uncatched ArgKind!");
  }
  TransAssert(0 && "Unreachable code!");
}
void ReduceClassTemplateParameter::removeOneParameterByArgType(
       const ClassTemplatePartialSpecializationDecl *PartialD,
       const TemplateArgument &Arg)
{
  TransAssert((Arg.getKind() == TemplateArgument::Type) && 
              "Arg is not TemplateArgument::Type!");
  llvm::DenseMap<const Type *, unsigned> TypeToVisitsCount;
  llvm::DenseMap<const Type *, const NamedDecl *> TypeToNamedDecl;
  llvm::DenseMap<const Type *, unsigned> TypeToIndex;

  // retrieve all TemplateTypeParmType
  const TemplateParameterList *TPList = PartialD->getTemplateParameters();
  unsigned Idx = 0;
  for (TemplateParameterList::const_iterator I = TPList->begin(),
       E = TPList->end(); I != E; ++I) {
    const NamedDecl *ND = (*I);
    const TemplateTypeParmDecl *TypeD = dyn_cast<TemplateTypeParmDecl>(ND);
    if (!TypeD) {
      Idx++;
      continue;
    }
    const Type *ParmTy = TypeD->getTypeForDecl();
    TypeToVisitsCount[ParmTy] = 0;
    TypeToNamedDecl[ParmTy] = ND;
    TypeToIndex[ParmTy] = Idx;
  }

  QualType QTy = Arg.getAsType();
  ArgumentDependencyVisitor V(TypeToVisitsCount);
  // collect TemplateTypeParmType being used by Arg
  V.TraverseType(QTy);

  llvm::DenseMap<const Type *, unsigned> DependentTypeToVisitsCount;
  for (llvm::DenseMap<const Type *, unsigned>::iterator 
         I = TypeToVisitsCount.begin(), E = TypeToVisitsCount.end();
       I != E; ++I) {
    if ((*I).second > 0)
      DependentTypeToVisitsCount[(*I).first] = 1;
  }

  // check if the used TemplateTypeParmType[s] have dependencies
  // on other Args. If yes, we cannot remove it from the parameter list.
  // For example:
  //   template <typename T>
  //   struct S <T*, T&> {};
  // removing either of the arguments needs to keep the template 
  // parameter
  ArgumentDependencyVisitor AccumV(DependentTypeToVisitsCount);
  
  const ASTTemplateArgumentListInfo *ArgList = 
    PartialD->getTemplateArgsAsWritten();
  
  const TemplateArgumentLoc *ArgLocs = ArgList->getTemplateArgs();
  unsigned NumArgs = ArgList->NumTemplateArgs;
  TransAssert((TheParameterIndex < NumArgs) && 
               "Bad NumArgs from partial template decl!");
  for (unsigned I = 0; I < NumArgs; ++I) {
    if (I == TheParameterIndex)
      continue;
    
    const TemplateArgumentLoc ArgLoc = ArgLocs[I];
    TemplateArgument OtherArg = ArgLoc.getArgument();
    if (OtherArg.isInstantiationDependent() && 
        (OtherArg.getKind() == TemplateArgument::Type)) {
      QualType QTy = OtherArg.getAsType();
      AccumV.TraverseType(QTy);
    }
  }

  for (llvm::DenseMap<const Type *, unsigned>::iterator 
         I = DependentTypeToVisitsCount.begin(), 
         E = DependentTypeToVisitsCount.end();
       I != E; ++I) {
    if ((*I).second != 1)
      continue;

    const NamedDecl *Param = TypeToNamedDecl[(*I).first];
    TransAssert(Param && "NULL Parameter!");
    SourceRange Range = Param->getSourceRange();
    removeParameterByRange(Range, TPList, TypeToIndex[(*I).first]);
  }
}