Esempio n. 1
0
SourceLocation RewriteUtils::getVarDeclTypeLocEnd(const VarDecl *VD)
{
  TypeLoc VarTypeLoc = VD->getTypeSourceInfo()->getTypeLoc();
  const IdentifierInfo *Id = VD->getType().getBaseTypeIdentifier();

  // handle a special case shown as below:
  // x;
  // *y[];
  // (*z)[];
  // void foo(void) {...}
  // where x implicitly has type of int, whereas y has type of int *
  if (!Id) {
    SourceLocation EndLoc = VD->getLocation();
    const char *Buf = SrcManager->getCharacterData(EndLoc);
    int Offset = -1;
    SourceLocation NewEndLoc = EndLoc.getLocWithOffset(Offset);
    if (!NewEndLoc.isValid())
      return EndLoc;

    Buf--;
    while (isspace(*Buf) || (*Buf == '*') || (*Buf == '(')) {
      Offset--;
      NewEndLoc = EndLoc.getLocWithOffset(Offset);
      if (!NewEndLoc.isValid())
        return EndLoc.getLocWithOffset(Offset+1);

      Buf--;
    }
    return EndLoc.getLocWithOffset(Offset+1);
  }

  TypeLoc NextTL = VarTypeLoc.getNextTypeLoc();
  while (!NextTL.isNull()) {
    VarTypeLoc = NextTL;
    NextTL = NextTL.getNextTypeLoc();
  }

  SourceRange TypeLocRange = VarTypeLoc.getSourceRange();
  SourceLocation EndLoc = getEndLocationFromBegin(TypeLocRange);
  TransAssert(EndLoc.isValid() && "Invalid EndLoc!");

  const Type *Ty = VarTypeLoc.getTypePtr();

  // I am not sure why, but for a declaration like below:
  //   unsigned int a; (or long long a;)
  // TypeLoc.getBeginLoc() returns the position of 'u'
  // TypeLoc.getEndLoc() also returns the position of 'u'
  // The size of TypeLoc.getSourceRange() is 8, which is the 
  // length of "unsigned"
  // Then we are getting trouble, because now EndLoc is right 
  // after 'd', but we need it points to the location after "int".
  // skipPossibleTypeRange corrects the above deviation
  // Or am I doing something horrible here?
  EndLoc = skipPossibleTypeRange(Ty, EndLoc, VD->getLocation());
  return EndLoc;
}
Esempio n. 2
0
SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
  if (DeclInfo) {
    TypeLoc TL = DeclInfo->getTypeLoc();
    while (true) {
      TypeLoc NextTL = TL.getNextTypeLoc();
      if (!NextTL)
        return TL.getSourceRange().getBegin();
      TL = NextTL;
    }
  }
  return SourceLocation();
}
void PassByValueCheck::check(const MatchFinder::MatchResult &Result) {
  const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("Ctor");
  const auto *ParamDecl = Result.Nodes.getNodeAs<ParmVarDecl>("Param");
  const auto *Initializer =
      Result.Nodes.getNodeAs<CXXCtorInitializer>("Initializer");
  SourceManager &SM = *Result.SourceManager;

  // If the parameter is used or anything other than the copy, do not apply
  // the changes.
  if (!paramReferredExactlyOnce(Ctor, ParamDecl))
    return;

  // If the parameter is trivial to copy, don't move it. Moving a trivivally
  // copyable type will cause a problem with misc-move-const-arg
  if (ParamDecl->getType().isTriviallyCopyableType(*Result.Context)) 
    return;

  auto Diag = diag(ParamDecl->getLocStart(), "pass by value and use std::move");

  // Iterate over all declarations of the constructor.
  for (const ParmVarDecl *ParmDecl : collectParamDecls(Ctor, ParamDecl)) {
    auto ParamTL = ParmDecl->getTypeSourceInfo()->getTypeLoc();
    auto RefTL = ParamTL.getAs<ReferenceTypeLoc>();

    // Do not replace if it is already a value, skip.
    if (RefTL.isNull())
      continue;

    TypeLoc ValueTL = RefTL.getPointeeLoc();
    auto TypeRange = CharSourceRange::getTokenRange(ParmDecl->getLocStart(),
                                                    ParamTL.getLocEnd());
    std::string ValueStr =
        Lexer::getSourceText(
            CharSourceRange::getTokenRange(ValueTL.getSourceRange()), SM,
            Result.Context->getLangOpts())
            .str();
    ValueStr += ' ';
    Diag << FixItHint::CreateReplacement(TypeRange, ValueStr);
  }

  // Use std::move in the initialization list.
  Diag << FixItHint::CreateInsertion(Initializer->getRParenLoc(), ")")
       << FixItHint::CreateInsertion(
              Initializer->getLParenLoc().getLocWithOffset(1), "std::move(");

  if (auto IncludeFixit = Inserter->CreateIncludeInsertion(
          Result.SourceManager->getFileID(Initializer->getSourceLocation()),
          "utility",
          /*IsAngled=*/true)) {
    Diag << *IncludeFixit;
  }
}
Esempio n. 4
0
void ConstructorParamReplacer::run(const MatchFinder::MatchResult &Result) {
  assert(IncludeManager && "Include directives manager not set.");
  SourceManager &SM = *Result.SourceManager;
  const CXXConstructorDecl *Ctor =
      Result.Nodes.getNodeAs<CXXConstructorDecl>(PassByValueCtorId);
  const ParmVarDecl *ParamDecl =
      Result.Nodes.getNodeAs<ParmVarDecl>(PassByValueParamId);
  const CXXCtorInitializer *Initializer =
      Result.Nodes.getNodeAs<CXXCtorInitializer>(PassByValueInitializerId);
  assert(Ctor && ParamDecl && Initializer && "Bad Callback, missing node.");

  // Check this now to avoid unnecessary work. The param locations are checked
  // later.
  if (!Owner.isFileModifiable(SM, Initializer->getSourceLocation()))
    return;

  // The parameter will be in an unspecified state after the move, so check if
  // the parameter is used for anything else other than the copy. If so do not
  // apply any changes.
  if (!paramReferredExactlyOnce(Ctor, ParamDecl))
    return;

  llvm::SmallVector<const ParmVarDecl *, 2> AllParamDecls;
  collectParamDecls(Ctor, ParamDecl, AllParamDecls);

  // Generate all replacements for the params.
  llvm::SmallVector<Replacement, 2> ParamReplaces;
  for (unsigned I = 0, E = AllParamDecls.size(); I != E; ++I) {
    TypeLoc ParamTL = AllParamDecls[I]->getTypeSourceInfo()->getTypeLoc();
    ReferenceTypeLoc RefTL = ParamTL.getAs<ReferenceTypeLoc>();
    SourceRange Range(AllParamDecls[I]->getLocStart(), ParamTL.getLocEnd());
    CharSourceRange CharRange = Lexer::makeFileCharRange(
        CharSourceRange::getTokenRange(Range), SM, LangOptions());

    // do not generate a replacement when the parameter is already a value
    if (RefTL.isNull())
      continue;

    // transform non-value parameters (e.g: const-ref) to values
    TypeLoc ValueTypeLoc = RefTL.getPointeeLoc();
    llvm::SmallString<32> ValueStr = Lexer::getSourceText(
        CharSourceRange::getTokenRange(ValueTypeLoc.getSourceRange()), SM,
        LangOptions());

    // If it's impossible to change one of the parameter (e.g: comes from an
    // unmodifiable header) quit the callback now, do not generate any changes.
    if (CharRange.isInvalid() || ValueStr.empty() ||
        !Owner.isFileModifiable(SM, CharRange.getBegin()))
      return;

    // 'const Foo &param' -> 'Foo param'
    //  ~~~~~~~~~~~           ~~~^
    ValueStr += ' ';
    ParamReplaces.push_back(Replacement(SM, CharRange, ValueStr));
  }

  // Reject the changes if the the risk level is not acceptable.
  if (!Owner.isAcceptableRiskLevel(RL_Reasonable)) {
    RejectedChanges++;
    return;
  }

  // if needed, include <utility> in the file that uses std::move()
  const FileEntry *STDMoveFile =
      SM.getFileEntryForID(SM.getFileID(Initializer->getLParenLoc()));
  const tooling::Replacement &IncludeReplace =
      IncludeManager->addAngledInclude(STDMoveFile, "utility");
  if (IncludeReplace.isApplicable()) {
    Owner.addReplacementForCurrentTU(IncludeReplace);
    AcceptedChanges++;
  }

  // const-ref params becomes values (const Foo & -> Foo)
  for (const Replacement *I = ParamReplaces.begin(), *E = ParamReplaces.end();
       I != E; ++I) {
    Owner.addReplacementForCurrentTU(*I);
  }
  AcceptedChanges += ParamReplaces.size();

  // move the value in the init-list
  Owner.addReplacementForCurrentTU(Replacement(
      SM, Initializer->getLParenLoc().getLocWithOffset(1), 0, "std::move("));
  Owner.addReplacementForCurrentTU(
      Replacement(SM, Initializer->getRParenLoc(), 0, ")"));
  AcceptedChanges += 2;
}