示例#1
0
bool FunctionMergePass::areTypesCompatible(const Type * from, const Type * to) {
  if (from->typeClass() != to->typeClass()) {
    if ((from->typeClass() == Type::Class || from->typeClass() == Type::Interface) &&
        (to->typeClass() == Type::Class || to->typeClass() == Type::Interface)) {
      return true;
    }

    return false;
  }

  switch (from->typeClass()) {
    case Type::Primitive: {
      const PrimitiveType * pFrom = static_cast<const PrimitiveType *>(from);
      const PrimitiveType * pTo = static_cast<const PrimitiveType *>(to);
      if (pFrom->typeId() == pTo->typeId()) {
        return true;
      }

      return false;
    }

    case Type::Class:
    case Type::Interface:
      // Any reference type is compatible with any other.
      return true;

    case Type::Struct:
      return TypeRelation::isEqual(from, to);

    case Type::Tuple: {
      const TupleType * ttFrom = static_cast<const TupleType *>(from);
      const TupleType * ttTo = static_cast<const TupleType *>(to);
      if (ttFrom->members().size() != ttTo->members().size()) {
        return false;
      }

      size_t memberSize = ttFrom->members().size();
      for (size_t i = 0; i < memberSize; ++i) {
        if (!areTypesCompatible(ttFrom->members()[i].type(), ttTo->members()[i].type())) {
          return false;
        }
      }

      return true;
    }


    case Type::Union: {
      const UnionType * fromType = cast<UnionType>(from);
      const UnionType * toType = cast<UnionType>(to);
      return areTypesCompatible(fromType->typeArgs(), toType->typeArgs());
    }

    default:
      diag.debug() << "Type not handled: " << from;
      return false;
  }
}
示例#2
0
bool FunctionMergePass::visitUnionCtorCast(CastExpr * from, CastExpr * to) {
  if (!areTypesCompatible(from->type(), to->type())) {
    reportDifference("Difference in type of union cast expr", from, to);
    return false;
  }

  return visitExpr(from->arg(), to->arg());
}
示例#3
0
bool FunctionMergePass::areTypesCompatible(QualifiedType from, QualifiedType to) {
  return areTypesCompatible(from.unqualified(), to.unqualified());
}
void InefficientAlgorithmCheck::check(const MatchFinder::MatchResult &Result) {
  const auto *AlgCall = Result.Nodes.getNodeAs<CallExpr>("IneffAlg");
  const auto *IneffCont =
      Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("IneffCont");
  bool PtrToContainer = false;
  if (!IneffCont) {
    IneffCont =
        Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("IneffContPtr");
    PtrToContainer = true;
  }
  const llvm::StringRef IneffContName = IneffCont->getName();
  const bool Unordered =
      IneffContName.find("unordered") != llvm::StringRef::npos;
  const bool Maplike = IneffContName.find("map") != llvm::StringRef::npos;

  // Store if the key type of the container is compatible with the value
  // that is searched for.
  QualType ValueType = AlgCall->getArg(2)->getType();
  QualType KeyType =
      IneffCont->getTemplateArgs()[0].getAsType().getCanonicalType();
  const bool CompatibleTypes = areTypesCompatible(KeyType, ValueType);

  // Check if the comparison type for the algorithm and the container matches.
  if (AlgCall->getNumArgs() == 4 && !Unordered) {
    const Expr *Arg = AlgCall->getArg(3);
    const QualType AlgCmp =
        Arg->getType().getUnqualifiedType().getCanonicalType();
    const unsigned CmpPosition =
        (IneffContName.find("map") == llvm::StringRef::npos) ? 1 : 2;
    const QualType ContainerCmp = IneffCont->getTemplateArgs()[CmpPosition]
                                      .getAsType()
                                      .getUnqualifiedType()
                                      .getCanonicalType();
    if (AlgCmp != ContainerCmp) {
      diag(Arg->getLocStart(),
           "different comparers used in the algorithm and the container");
      return;
    }
  }

  const auto *AlgDecl = AlgCall->getDirectCallee();
  if (!AlgDecl)
    return;

  if (Unordered && AlgDecl->getName().find("bound") != llvm::StringRef::npos)
    return;

  const auto *AlgParam = Result.Nodes.getNodeAs<Expr>("AlgParam");
  const auto *IneffContExpr = Result.Nodes.getNodeAs<Expr>("IneffContExpr");
  FixItHint Hint;

  SourceManager &SM = *Result.SourceManager;
  LangOptions LangOpts = Result.Context->getLangOpts();

  CharSourceRange CallRange =
      CharSourceRange::getTokenRange(AlgCall->getSourceRange());

  // FIXME: Create a common utility to extract a file range that the given token
  // sequence is exactly spelled at (without macro argument expansions etc.).
  // We can't use Lexer::makeFileCharRange here, because for
  //
  //   #define F(x) x
  //   x(a b c);
  //
  // it will return "x(a b c)", when given the range "a"-"c". It makes sense for
  // removals, but not for replacements.
  //
  // This code is over-simplified, but works for many real cases.
  if (SM.isMacroArgExpansion(CallRange.getBegin()) &&
      SM.isMacroArgExpansion(CallRange.getEnd())) {
    CallRange.setBegin(SM.getSpellingLoc(CallRange.getBegin()));
    CallRange.setEnd(SM.getSpellingLoc(CallRange.getEnd()));
  }

  if (!CallRange.getBegin().isMacroID() && !Maplike && CompatibleTypes) {
    StringRef ContainerText = Lexer::getSourceText(
        CharSourceRange::getTokenRange(IneffContExpr->getSourceRange()), SM,
        LangOpts);
    StringRef ParamText = Lexer::getSourceText(
        CharSourceRange::getTokenRange(AlgParam->getSourceRange()), SM,
        LangOpts);
    std::string ReplacementText =
        (llvm::Twine(ContainerText) + (PtrToContainer ? "->" : ".") +
         AlgDecl->getName() + "(" + ParamText + ")")
            .str();
    Hint = FixItHint::CreateReplacement(CallRange, ReplacementText);
  }

  diag(AlgCall->getLocStart(),
       "this STL algorithm call should be replaced with a container method")
      << Hint;
}