Ejemplo n.º 1
0
/// ParseDirective - Go through the comment and see if it indicates expected
/// diagnostics. If so, then put them in the appropriate directive list.
///
/// Returns true if any valid directives were found.
static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
                           SourceLocation Pos, DiagnosticsEngine &Diags,
                           VerifyDiagnosticConsumer::DirectiveStatus &Status) {
  // A single comment may contain multiple directives.
  bool FoundDirective = false;
  for (ParseHelper PH(S); !PH.Done();) {
    // Search for token: expected
    if (!PH.Search("expected", true))
      break;
    PH.Advance();

    // Next token: -
    if (!PH.Next("-"))
      continue;
    PH.Advance();

    // Next token: { error | warning | note }
    DirectiveList* DL = NULL;
    if (PH.Next("error"))
      DL = ED ? &ED->Errors : NULL;
    else if (PH.Next("warning"))
      DL = ED ? &ED->Warnings : NULL;
    else if (PH.Next("note"))
      DL = ED ? &ED->Notes : NULL;
    else if (PH.Next("no-diagnostics")) {
      if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
        Diags.Report(Pos, diag::err_verify_invalid_no_diags)
          << /*IsExpectedNoDiagnostics=*/true;
      else
        Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
      continue;
    } else
      continue;
    PH.Advance();

    if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
      Diags.Report(Pos, diag::err_verify_invalid_no_diags)
        << /*IsExpectedNoDiagnostics=*/false;
      continue;
    }
    Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives;

    // If a directive has been found but we're not interested
    // in storing the directive information, return now.
    if (!DL)
      return true;

    // Default directive kind.
    bool RegexKind = false;
    const char* KindStr = "string";

    // Next optional token: -
    if (PH.Next("-re")) {
      PH.Advance();
      RegexKind = true;
      KindStr = "regex";
    }

    // Next optional token: @
    SourceLocation ExpectedLoc;
    if (!PH.Next("@")) {
      ExpectedLoc = Pos;
    } else {
      PH.Advance();
      unsigned Line = 0;
      bool FoundPlus = PH.Next("+");
      if (FoundPlus || PH.Next("-")) {
        // Relative to current line.
        PH.Advance();
        bool Invalid = false;
        unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid);
        if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
          if (FoundPlus) ExpectedLine += Line;
          else ExpectedLine -= Line;
          ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1);
        }
      } else {
        // Absolute line number.
        if (PH.Next(Line) && Line > 0)
          ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1);
      }

      if (ExpectedLoc.isInvalid()) {
        Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                     diag::err_verify_missing_line) << KindStr;
        continue;
      }
      PH.Advance();
    }

    // Skip optional whitespace.
    PH.SkipWhitespace();

    // Next optional token: positive integer or a '+'.
    unsigned Min = 1;
    unsigned Max = 1;
    if (PH.Next(Min)) {
      PH.Advance();
      // A positive integer can be followed by a '+' meaning min
      // or more, or by a '-' meaning a range from min to max.
      if (PH.Next("+")) {
        Max = Directive::MaxCount;
        PH.Advance();
      } else if (PH.Next("-")) {
        PH.Advance();
        if (!PH.Next(Max) || Max < Min) {
          Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                       diag::err_verify_invalid_range) << KindStr;
          continue;
        }
        PH.Advance();
      } else {
        Max = Min;
      }
    } else if (PH.Next("+")) {
      // '+' on its own means "1 or more".
      Max = Directive::MaxCount;
      PH.Advance();
    }

    // Skip optional whitespace.
    PH.SkipWhitespace();

    // Next token: {{
    if (!PH.Next("{{")) {
      Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                   diag::err_verify_missing_start) << KindStr;
      continue;
    }
    PH.Advance();
    const char* const ContentBegin = PH.C; // mark content begin

    // Search for token: }}
    if (!PH.Search("}}")) {
      Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                   diag::err_verify_missing_end) << KindStr;
      continue;
    }
    const char* const ContentEnd = PH.P; // mark content end
    PH.Advance();

    // Build directive text; convert \n to newlines.
    std::string Text;
    StringRef NewlineStr = "\\n";
    StringRef Content(ContentBegin, ContentEnd-ContentBegin);
    size_t CPos = 0;
    size_t FPos;
    while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
      Text += Content.substr(CPos, FPos-CPos);
      Text += '\n';
      CPos = FPos + NewlineStr.size();
    }
    if (Text.empty())
      Text.assign(ContentBegin, ContentEnd);

    // Construct new directive.
    Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text,
                                     Min, Max);
    std::string Error;
    if (D->isValid(Error)) {
      DL->push_back(D);
      FoundDirective = true;
    } else {
      Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
                   diag::err_verify_invalid_content)
        << KindStr << Error;
    }
  }

  return FoundDirective;
}
Ejemplo n.º 2
0
/// Finish - This does final analysis of the declspec, rejecting things like
/// "_Imaginary" (lacking an FP type).  This returns a diagnostic to issue or
/// diag::NUM_DIAGNOSTICS if there is no error.  After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
    // Before possibly changing their values, save specs as written.
    SaveWrittenBuiltinSpecs();
    SaveStorageSpecifierAsWritten();

    // Check the type specifier components first.

    // Validate and finalize AltiVec vector declspec.
    if (TypeAltiVecVector) {
        if (TypeAltiVecBool) {
            // Sign specifiers are not allowed with vector bool. (PIM 2.1)
            if (TypeSpecSign != TSS_unspecified) {
                Diag(D, TSSLoc, diag::err_invalid_vector_bool_decl_spec)
                        << getSpecifierName((TSS)TypeSpecSign);
            }

            // Only char/int are valid with vector bool. (PIM 2.1)
            if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) &&
                    (TypeSpecType != TST_int)) || TypeAltiVecPixel) {
                Diag(D, TSTLoc, diag::err_invalid_vector_bool_decl_spec)
                        << (TypeAltiVecPixel ? "__pixel" :
                            getSpecifierName((TST)TypeSpecType));
            }

            // Only 'short' is valid with vector bool. (PIM 2.1)
            if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short))
                Diag(D, TSWLoc, diag::err_invalid_vector_bool_decl_spec)
                        << getSpecifierName((TSW)TypeSpecWidth);

            // Elements of vector bool are interpreted as unsigned. (PIM 2.1)
            if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) ||
                    (TypeSpecWidth != TSW_unspecified))
                TypeSpecSign = TSS_unsigned;
        }

        if (TypeAltiVecPixel) {
            //TODO: perform validation
            TypeSpecType = TST_int;
            TypeSpecSign = TSS_unsigned;
            TypeSpecWidth = TSW_short;
            TypeSpecOwned = false;
        }
    }

    // signed/unsigned are only valid with int/char/wchar_t.
    if (TypeSpecSign != TSS_unspecified) {
        if (TypeSpecType == TST_unspecified)
            TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int.
        else if (TypeSpecType != TST_int  && TypeSpecType != TST_int128 &&
                 TypeSpecType != TST_char && TypeSpecType != TST_wchar) {
            Diag(D, TSSLoc, diag::err_invalid_sign_spec)
                    << getSpecifierName((TST)TypeSpecType);
            // signed double -> double.
            TypeSpecSign = TSS_unspecified;
        }
    }

    // Validate the width of the type.
    switch (TypeSpecWidth) {
    case TSW_unspecified:
        break;
    case TSW_short:    // short int
    case TSW_longlong: // long long int
        if (TypeSpecType == TST_unspecified)
            TypeSpecType = TST_int; // short -> short int, long long -> long long int.
        else if (TypeSpecType != TST_int) {
            Diag(D, TSWLoc,
                 TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec
                 : diag::err_invalid_longlong_spec)
                    <<  getSpecifierName((TST)TypeSpecType);
            TypeSpecType = TST_int;
            TypeSpecOwned = false;
        }
        break;
    case TSW_long:  // long double, long int
        if (TypeSpecType == TST_unspecified)
            TypeSpecType = TST_int;  // long -> long int.
        else if (TypeSpecType != TST_int && TypeSpecType != TST_double) {
            Diag(D, TSWLoc, diag::err_invalid_long_spec)
                    << getSpecifierName((TST)TypeSpecType);
            TypeSpecType = TST_int;
            TypeSpecOwned = false;
        }
        break;
    }

    // TODO: if the implementation does not implement _Complex or _Imaginary,
    // disallow their use.  Need information about the backend.
    if (TypeSpecComplex != TSC_unspecified) {
        if (TypeSpecType == TST_unspecified) {
            Diag(D, TSCLoc, diag::ext_plain_complex)
                    << FixItHint::CreateInsertion(
                        PP.getLocForEndOfToken(getTypeSpecComplexLoc()),
                        " double");
            TypeSpecType = TST_double;   // _Complex -> _Complex double.
        } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
            // Note that this intentionally doesn't include _Complex _Bool.
            if (!PP.getLangOpts().CPlusPlus)
                Diag(D, TSTLoc, diag::ext_integer_complex);
        } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
            Diag(D, TSCLoc, diag::err_invalid_complex_spec)
                    << getSpecifierName((TST)TypeSpecType);
            TypeSpecComplex = TSC_unspecified;
        }
    }

    // If no type specifier was provided and we're parsing a language where
    // the type specifier is not optional, but we got 'auto' as a storage
    // class specifier, then assume this is an attempt to use C++0x's 'auto'
    // type specifier.
    // FIXME: Does Microsoft really support implicit int in C++?
    if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().MicrosoftExt &&
            TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) {
        TypeSpecType = TST_auto;
        StorageClassSpec = StorageClassSpecAsWritten = SCS_unspecified;
        TSTLoc = TSTNameLoc = StorageClassSpecLoc;
        StorageClassSpecLoc = SourceLocation();
    }
    // Diagnose if we've recovered from an ill-formed 'auto' storage class
    // specifier in a pre-C++0x dialect of C++.
    if (!PP.getLangOpts().CPlusPlus0x && TypeSpecType == TST_auto)
        Diag(D, TSTLoc, diag::ext_auto_type_specifier);
    if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus0x &&
            StorageClassSpec == SCS_auto)
        Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class)
                << FixItHint::CreateRemoval(StorageClassSpecLoc);
    if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32)
        Diag(D, TSTLoc, diag::warn_cxx98_compat_unicode_type)
                << (TypeSpecType == TST_char16 ? "char16_t" : "char32_t");
    if (Constexpr_specified)
        Diag(D, ConstexprLoc, diag::warn_cxx98_compat_constexpr);

    // C++ [class.friend]p6:
    //   No storage-class-specifier shall appear in the decl-specifier-seq
    //   of a friend declaration.
    if (isFriendSpecified() && getStorageClassSpec()) {
        DeclSpec::SCS SC = getStorageClassSpec();
        const char *SpecName = getSpecifierName(SC);

        SourceLocation SCLoc = getStorageClassSpecLoc();
        SourceLocation SCEndLoc = SCLoc.getLocWithOffset(strlen(SpecName));

        Diag(D, SCLoc, diag::err_friend_storage_spec)
                << SpecName
                << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc));

        ClearStorageClassSpecs();
    }

    assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType));

    // Okay, now we can infer the real type.

    // TODO: return "auto function" and other bad things based on the real type.

    // 'data definition has no type or storage class'?
}
  // Add the input to the memory buffer, parse it, and add it to the AST.
  IncrementalParser::EParseResult 
  IncrementalParser::Parse(llvm::StringRef input) {
    Preprocessor& PP = m_CI->getPreprocessor();
    DiagnosticConsumer& DClient = m_CI->getDiagnosticClient();

    PP.enableIncrementalProcessing();

    DClient.BeginSourceFile(m_CI->getLangOpts(), &PP);
    // Reset the transaction information
    getLastTransaction().setBeforeFirstDecl(getCI()->getSema().CurContext);
    

    if (input.size()) {
      std::ostringstream source_name;
      source_name << "input_line_" << (m_MemoryBuffer.size() + 1);
      llvm::MemoryBuffer* MB  
        = llvm::MemoryBuffer::getMemBufferCopy(input, source_name.str());
      m_MemoryBuffer.push_back(MB);
      SourceManager& SM = getCI()->getSourceManager();

      // Create SourceLocation, which will allow clang to order the overload
      // candidates for example
      SourceLocation NewLoc = SM.getLocForStartOfFile(m_VirtualFileID);
      NewLoc = NewLoc.getLocWithOffset(m_MemoryBuffer.size() + 1);
      
      // Create FileID for the current buffer
      FileID FID = SM.createFileIDForMemBuffer(m_MemoryBuffer.back(),
                                               /*LoadedID*/0,
                                               /*LoadedOffset*/0, NewLoc);
      
      PP.EnterSourceFile(FID, 0, NewLoc);      
    }

    Parser::DeclGroupPtrTy ADecl;

    while (!m_Parser->ParseTopLevelDecl(ADecl)) {
      // Not end of file.
      // If we got a null return and something *was* parsed, ignore it.  This
      // is due to a top-level semicolon, an action override, or a parse error
      // skipping something.
      if (ADecl) {
        DeclGroupRef DGR = ADecl.getAsVal<DeclGroupRef>();
        for (DeclGroupRef::iterator i=DGR.begin(); i< DGR.end(); ++i) {
         if (!m_FirstTopLevelDecl)
           m_FirstTopLevelDecl = *((*i)->getDeclContext()->decls_begin());

          m_LastTopLevelDecl = *i;
        } 
        m_Consumer->HandleTopLevelDecl(DGR);
      } // ADecl
    };
    
    // Process any TopLevelDecls generated by #pragma weak.
    for (llvm::SmallVector<Decl*,2>::iterator
           I = getCI()->getSema().WeakTopLevelDecls().begin(),
           E = getCI()->getSema().WeakTopLevelDecls().end(); I != E; ++I) {
      m_Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
    }

    getCI()->getSema().PerformPendingInstantiations();

    DClient.EndSourceFile();

    PP.enableIncrementalProcessing(false);

    DiagnosticsEngine& Diag = getCI()->getSema().getDiagnostics();
    if (Diag.hasErrorOccurred())
      return IncrementalParser::kFailed;
    else if (Diag.getNumWarnings())
      return IncrementalParser::kSuccessWithWarnings;

    return IncrementalParser::kSuccess;
  }
void IncludeOrderPPCallbacks::EndOfMainFile() {
  LookForMainModule = true;
  if (IncludeDirectives.empty())
    return;

  // TODO: find duplicated includes.

  // Form blocks of includes. We don't want to sort across blocks. This also
  // implicitly makes us never reorder over #defines or #if directives.
  // FIXME: We should be more careful about sorting below comments as we don't
  // know if the comment refers to the next include or the whole block that
  // follows.
  std::vector<unsigned> Blocks(1, 0);
  for (unsigned I = 1, E = IncludeDirectives.size(); I != E; ++I)
    if (SM.getExpansionLineNumber(IncludeDirectives[I].Loc) !=
        SM.getExpansionLineNumber(IncludeDirectives[I - 1].Loc) + 1)
      Blocks.push_back(I);
  Blocks.push_back(IncludeDirectives.size()); // Sentinel value.

  // Get a vector of indices.
  std::vector<unsigned> IncludeIndices;
  for (unsigned I = 0, E = IncludeDirectives.size(); I != E; ++I)
    IncludeIndices.push_back(I);

  // Sort the includes. We first sort by priority, then lexicographically.
  for (unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI)
    std::sort(IncludeIndices.begin() + Blocks[BI],
              IncludeIndices.begin() + Blocks[BI + 1],
              [this](unsigned LHSI, unsigned RHSI) {
      IncludeDirective &LHS = IncludeDirectives[LHSI];
      IncludeDirective &RHS = IncludeDirectives[RHSI];

      int PriorityLHS =
          getPriority(LHS.Filename, LHS.IsAngled, LHS.IsMainModule);
      int PriorityRHS =
          getPriority(RHS.Filename, RHS.IsAngled, RHS.IsMainModule);

      return std::tie(PriorityLHS, LHS.Filename) <
             std::tie(PriorityRHS, RHS.Filename);
    });

  // Emit a warning for each block and fixits for all changes within that block.
  for (unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI) {
    // Find the first include that's not in the right position.
    unsigned I, E;
    for (I = Blocks[BI], E = Blocks[BI + 1]; I != E; ++I)
      if (IncludeIndices[I] != I)
        break;

    if (I == E)
      continue;

    // Emit a warning.
    auto D = Check.diag(IncludeDirectives[I].Loc,
                        "#includes are not sorted properly");

    // Emit fix-its for all following includes in this block.
    for (; I != E; ++I) {
      if (IncludeIndices[I] == I)
        continue;
      const IncludeDirective &CopyFrom = IncludeDirectives[IncludeIndices[I]];

      SourceLocation FromLoc = CopyFrom.Range.getBegin();
      const char *FromData = SM.getCharacterData(FromLoc);
      unsigned FromLen = std::strcspn(FromData, "\n");

      StringRef FixedName(FromData, FromLen);

      SourceLocation ToLoc = IncludeDirectives[I].Range.getBegin();
      const char *ToData = SM.getCharacterData(ToLoc);
      unsigned ToLen = std::strcspn(ToData, "\n");
      auto ToRange =
          CharSourceRange::getCharRange(ToLoc, ToLoc.getLocWithOffset(ToLen));

      D << FixItHint::CreateReplacement(ToRange, FixedName);
    }
  }

  IncludeDirectives.clear();
}
Ejemplo n.º 5
0
bool RewriteUtils::removeArgFromExpr(const Expr *E,
                                     int ParamPos)
{
  
  if (ParamPos >= static_cast<int>(getNumArgsWrapper(E)))
    return true;

  const Expr *Arg = getArgWrapper(E, ParamPos);
  TransAssert(Arg && "Null arg!");
  if (dyn_cast<CXXDefaultArgExpr>(Arg->IgnoreParenCasts()))
    return true;

  SourceRange ArgRange = Arg->getSourceRange();
  int RangeSize = TheRewriter->getRangeSize(ArgRange);

  if (RangeSize == -1)
    return false;

  SourceLocation StartLoc = ArgRange.getBegin();
  unsigned int NumArgs = getNumArgsWrapper(E);

  if ((ParamPos == 0) && ((NumArgs == 1) ||
                          ((NumArgs > 1) && 
                           dyn_cast<CXXDefaultArgExpr>(
                           getArgWrapper(E, 1)->IgnoreParenCasts())))) {
    // Note that ')' is included in ParamLocRange
    return !(TheRewriter->RemoveText(ArgRange));
  }

  int LastArgPos = static_cast<int>(NumArgs - 1);
  // The param is the last non-default parameter
  if ((ParamPos == LastArgPos) ||
      ((ParamPos < LastArgPos) &&
        dyn_cast<CXXDefaultArgExpr>(
          getArgWrapper(E, ParamPos+1)->IgnoreParenCasts()))) {
    int Offset = 0;
    const char *StartBuf = SrcManager->getCharacterData(StartLoc);

    TransAssert(StartBuf && "Invalid start buffer!");
    while (*StartBuf != ',') {
      StartBuf--;
      Offset--;
    }

    SourceLocation NewStartLoc = StartLoc.getLocWithOffset(Offset);
    return !(TheRewriter->RemoveText(NewStartLoc,
                                     RangeSize - Offset));
  }

  // We cannot use SrcManager->getCharacterData(StartLoc) to get the buffer,
  // because it returns the unmodified string. I've tried to use 
  // getEndlocationUntil(ArgRange, ",", ...) call, but still failed. 
  // Seems in some cases, it returns bad results for a complex case like:
  //  foo(...foo(...), ...)
  // So I ended up with this ugly way - get the end loc from the next arg.
  const Expr *NextArg = getArgWrapper(E, ParamPos+1);
  SourceRange NextArgRange = NextArg->getSourceRange();
  SourceLocation NextStartLoc = NextArgRange.getBegin();
  const char *NextStartBuf = SrcManager->getCharacterData(NextStartLoc);
  int Offset = 0;
  while (*NextStartBuf != ',') {
      NextStartBuf--;
      Offset--;
  }

  SourceLocation NewEndLoc = NextStartLoc.getLocWithOffset(Offset);
  return !TheRewriter->RemoveText(SourceRange(StartLoc, NewEndLoc));
}
Ejemplo n.º 6
0
static bool fillRanges(MemoryBuffer *Code,
                       std::vector<tooling::Range> &Ranges) {
  IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
      new vfs::InMemoryFileSystem);
  FileManager Files(FileSystemOptions(), InMemoryFileSystem);
  DiagnosticsEngine Diagnostics(
      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
      new DiagnosticOptions);
  SourceManager Sources(Diagnostics, Files);
  FileID ID = createInMemoryFile("<irrelevant>", Code, Sources, Files,
                                 InMemoryFileSystem.get());
  if (!LineRanges.empty()) {
    if (!Offsets.empty() || !Lengths.empty()) {
      errs() << "error: cannot use -lines with -offset/-length\n";
      return true;
    }

    for (unsigned i = 0, e = LineRanges.size(); i < e; ++i) {
      unsigned FromLine, ToLine;
      if (parseLineRange(LineRanges[i], FromLine, ToLine)) {
        errs() << "error: invalid <start line>:<end line> pair\n";
        return true;
      }
      if (FromLine > ToLine) {
        errs() << "error: start line should be less than end line\n";
        return true;
      }
      SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1);
      SourceLocation End = Sources.translateLineCol(ID, ToLine, UINT_MAX);
      if (Start.isInvalid() || End.isInvalid())
        return true;
      unsigned Offset = Sources.getFileOffset(Start);
      unsigned Length = Sources.getFileOffset(End) - Offset;
      Ranges.push_back(tooling::Range(Offset, Length));
    }
    return false;
  }

  if (Offsets.empty())
    Offsets.push_back(0);
  if (Offsets.size() != Lengths.size() &&
      !(Offsets.size() == 1 && Lengths.empty())) {
    errs() << "error: number of -offset and -length arguments must match.\n";
    return true;
  }
  for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
    if (Offsets[i] >= Code->getBufferSize()) {
      errs() << "error: offset " << Offsets[i] << " is outside the file\n";
      return true;
    }
    SourceLocation Start =
        Sources.getLocForStartOfFile(ID).getLocWithOffset(Offsets[i]);
    SourceLocation End;
    if (i < Lengths.size()) {
      if (Offsets[i] + Lengths[i] > Code->getBufferSize()) {
        errs() << "error: invalid length " << Lengths[i]
               << ", offset + length (" << Offsets[i] + Lengths[i]
               << ") is outside the file.\n";
        return true;
      }
      End = Start.getLocWithOffset(Lengths[i]);
    } else {
      End = Sources.getLocForEndOfFile(ID);
    }
    unsigned Offset = Sources.getFileOffset(Start);
    unsigned Length = Sources.getFileOffset(End) - Offset;
    Ranges.push_back(tooling::Range(Offset, Length));
  }
  return false;
}
Ejemplo n.º 7
0
/// \brief 'Loc' is the end of a statement range. This returns the location
/// immediately after the semicolon following the statement.
/// If no semicolon is found or the location is inside a macro, the returned
/// source location will be invalid.
SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx) {
    SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx);
    if (SemiLoc.isInvalid())
        return SourceLocation();
    return SemiLoc.getLocWithOffset(1);
}
Ejemplo n.º 8
0
CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const {
  SourceLocation Loc = SM.getLocForStartOfFile(InsertFromRangeOffs.getFID());
  Loc = Loc.getLocWithOffset(InsertFromRangeOffs.getOffset());
  assert(Loc.isFileID());
  return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length));
}
Ejemplo n.º 9
0
void TypeRenameTransform::processFunctionDecl(FunctionDecl *D)
{
  // if no type source info, it's a void f(void) function
  auto TSI = D->getTypeSourceInfo();
  if (TSI) {      
    processTypeLoc(TSI->getTypeLoc());
  }

  // handle ctor name initializers
  if (auto CD = dyn_cast<CXXConstructorDecl>(D)) {
    auto BL = CD->getLocation();
    std::string newName;
    if (BL.isValid() && CD->getParent()->getLocation() != BL && 
        nameMatches(CD->getParent(), newName, true)) {
      renameLocation(BL, newName);
    }
    
    for (auto II = CD->init_begin(), IE = CD->init_end(); II != IE; ++II) {
      if ((*II)->isBaseInitializer()) {
        processTypeLoc((*II)->getBaseClassLoc());        
      }
      
      auto X = (*II)->getInit();
      if (X) {
        processStmt(X);
      }
    }
  }
  
  // dtor
  if (auto DD = dyn_cast<CXXDestructorDecl>(D)) {
    // if parent matches
    auto BL = DD->getLocation();
    std::string newName;
    auto P = DD->getParent();
    if (BL.isValid() && P->getLocation() != BL &&
        nameMatches(P, newName, true)) {
    
      // can't use renameLocation since this is a tricky case        
    
      // need to use raw_identifier because Lexer::findLocationAfterToken
      // performs a raw lexing
      SourceLocation EL =
        Lexer::findLocationAfterToken(BL, tok::raw_identifier,
                                      sema->getSourceManager(),
                                      sema->getLangOpts(), false);


      // TODO: Find the right way to do this -- consider this a hack

      // llvm::errs() << indent() << "dtor at: " << loc(BL) << ", locStart: " << loc(DD->getLocStart())
      //   << ", nameAsString: " << P->getNameAsString() << ", len: " << P->getNameAsString().size()
      //   << ", DD nameAsString: " << DD->getNameAsString() << ", len: " << DD->getNameAsString().size()
      //   << "\n";
        
      if (EL.isValid()) {
        // EL is 1 char after the dtor name ~Foo, so -1 == pos of 'o'
        SourceLocation NE = EL.getLocWithOffset(-1);
        
        // we use the parent's name to see how much we should back off
        // if we use  D->getNameAsString(), we'd run into two problems:
        //   (1) the name would be ~Foo
        //   (2) the name for template class dtor would be ~Foo<T>
        SourceLocation NB =
          EL.getLocWithOffset(-(int)P->getNameAsString().size());

        if (NB.isMacroID()) {
          // TODO: emit error
          llvm::errs() << "Warning: Token is resulted from macro expansion"
            " and is therefore not renamed, at: " << loc(NB) << "\n";
        }
        else {
        // TODO: Determine if it's a wrtiable file
    
        // TODO: Determine if the location has already been touched or
        // needs skipping (such as in refactoring API user's code, then
        // the API headers need no changing since later the new API will be
        // in place)              
          replace(SourceRange(NB, NE), newName);
        }
      }
    }
  }
  
  // rename the params' types
  for (auto PI = D->param_begin(), PE = D->param_end(); PI != PE; ++PI) {
    processParmVarDecl(*PI);
  }
  
  // the name itself
  processQualifierLoc(D->getQualifierLoc());
  
  // handle body
  
  if (auto B = D->getBody()) {
    if (stmtInSameFileAsDecl(B, D)) {
      // llvm::errs() << indent() << "body? " << D->getBody() << "\n";
      processStmt(B);
    }
  }  
}
Ejemplo n.º 10
0
SourceLocation Commit::Edit::getFileLocation(SourceManager &SM) const {
  SourceLocation Loc = SM.getLocForStartOfFile(Offset.getFID());
  Loc = Loc.getLocWithOffset(Offset.getOffset());
  assert(Loc.isFileID());
  return Loc;
}
Ejemplo n.º 11
0
CharSourceRange Commit::Edit::getFileRange(SourceManager &SM) const {
  SourceLocation Loc = getFileLocation(SM);
  return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length));
}
Ejemplo n.º 12
0
	clang::StmtResult InsiemeSema::ActOnCompoundStmt(clang::SourceLocation L, clang::SourceLocation R, llvm::ArrayRef<clang::Stmt*> Elts, bool isStmtExpr) {
		// we parse the original code segment, within the original locations
		StmtResult&& ret = Sema::ActOnCompoundStmt(L, R, std::move(Elts), isStmtExpr);
		clang::CompoundStmt* CS = cast<clang::CompoundStmt>(ret.get());
		
		// This is still buggy as of Clang 3.6.2:
		// when pragmas are just after the beginning of a compound stmt, example:
		// {
		// 		#pragma xxx
		// 		...
		// }
		// the location of the opening bracket is wrong because of a bug in the clang parser.
		//
		// We solve the problem by searching for the bracket in the input stream and overwrite
		// the value of L (which contains the wrong location) with the correct value.

		enum { MacroIDBit = 1U << 31 }; // from clang/Basic/SourceLocation.h for use with cpp classes
		{
			SourceLocation&& leftBracketLoc = SourceMgr.getImmediateSpellingLoc(L);
			std::pair<FileID, unsigned>&& locInfo = SourceMgr.getDecomposedLoc(leftBracketLoc);
			llvm::StringRef&& buffer = SourceMgr.getBufferData(locInfo.first);
			const char* strData = buffer.begin() + locInfo.second;
			char const* lBracePos = strbchr(strData, buffer.begin(), '{');

			// We know the location of the left bracket, we overwrite the value of L with the correct location
			// but only if the location is valid as in getFileLocWithOffset() in SourceLocation
			if((((leftBracketLoc.getRawEncoding() & ~MacroIDBit) + (lBracePos - strData)) & MacroIDBit) == 0) {
				L = leftBracketLoc.getLocWithOffset(lBracePos - strData);
			}
		}

		// For the right bracket, we start at the final statement in the compound 
		//   (or its start if it is empty) and search forward until we find the first "}"
		// Otherwise, cases such as this:
		//
		// {
		//    bla();
		// }
		// #pragma test expect_ir(R"( {} )")
		//
		// will be broken

		{
			SourceLocation rightBracketLoc;
			if(CS->size() == 0) {
				rightBracketLoc = SourceMgr.getImmediateSpellingLoc(L);
			} else {
				rightBracketLoc = SourceMgr.getImmediateSpellingLoc(CS->body_back()->getLocEnd());
			}
			std::pair<FileID, unsigned>&& locInfo = SourceMgr.getDecomposedLoc(rightBracketLoc);
			llvm::StringRef buffer = SourceMgr.getBufferData(locInfo.first);
			const char* strData = buffer.begin() + locInfo.second;
			char const* rBracePos = strchr(strData, '}');

			// We know the location of the right bracket, we overwrite the value of R with the correct location
			if((((rightBracketLoc.getRawEncoding() & ~MacroIDBit) + (rBracePos - strData)) & MacroIDBit) == 0) {
				R = rightBracketLoc.getLocWithOffset(rBracePos - strData);
			}
		}
		
		// the source range we inspect is defined by the new source locations,
		// this fix the problem with boundaries jumping to the beginning of the file in
		// the macro expansions:
		//
		//	#define F(x) { }
		//
		//		...
		//
		//		F(r)    // <-this statement will jum to the macro location
		//
		PragmaList matched;
		SourceRange SR(L, R);

		// for each of the pragmas in the range between brackets
		for(PragmaFilter&& filter = PragmaFilter(SR, SourceMgr, pimpl->pending_pragma); *filter; ++filter) {
			PragmaPtr P = *filter;

			unsigned int pragmaStart = utils::Line(P->getStartLocation(), SourceMgr);
			unsigned int pragmaEnd = utils::Line(P->getEndLocation(), SourceMgr);

			bool found = false;
			// problem with first pragma, compound start is delayed until fist usable line (first stmt)
			if(CS->size() > 0) {
				for(clang::CompoundStmt::body_iterator it = CS->body_begin(); it != CS->body_end(); ++it) {
					unsigned int stmtStart = (Line((*it)->getLocStart(), SourceMgr));

					if((pragmaEnd <= stmtStart)) {
						// ACHTUNG: if the node is a nullStmt, and is not at the end of the compound (in
						// which case is most probably ours) we can not trust it. semantics wont change,
						// we move one more. (BUG: nullStmt followed by pragmas, the source begin is
						// postponed until next stmt) this makes pragmas to be attached to a previous
						// stmt
						if(!llvm::isa<clang::NullStmt>(*it)) {
							// this pragma is attached to the current stmt
							P->setStatement(*it);
							matched.push_back(P);
							found = true;
							break;
						}
					}
				}
			}
			if(!found && pragmaStart <= utils::Line(R, SourceMgr)) {
				// this is a de-attached pragma (barrier i.e.) at the end of the compound
				// we need to create a fake NullStmt ( ; ) to attach this
				Stmt** stmts = new Stmt*[CS->size() + 1];

				ArrayRef<clang::Stmt*> stmtList(stmts, CS->size() + 1);

				clang::CompoundStmt* newCS =
				    new(Context) clang::CompoundStmt(Context, stmtList, CS->getSourceRange().getBegin(), CS->getSourceRange().getEnd());

				std::copy(CS->body_begin(), CS->body_end(), newCS->body_begin());
				std::for_each(CS->body_begin(), CS->body_end(), [&](Stmt*& curr) { this->Context.Deallocate(curr); });
				newCS->setLastStmt(new(Context) NullStmt(SourceLocation()));

				P->setStatement(*newCS->body_rbegin());
				matched.push_back(P);

				// transfer the ownership of the statement
				clang::CompoundStmt* oldStmt = ret.getAs<clang::CompoundStmt>();
				oldStmt->setStmts(Context, NULL, 0);
				ret = newCS;
				CS = newCS;

				// destroy the old compound stmt
				Context.Deallocate(oldStmt);
				delete[] stmts;
			}
		}
		// remove matched pragmas
		EraseMatchedPragmas(pimpl->pending_pragma, matched);

		return std::move(ret);
	}
Ejemplo n.º 13
0
void NamespaceCommentCheck::check(const MatchFinder::MatchResult &Result) {
  const NamespaceDecl *ND = Result.Nodes.getNodeAs<NamespaceDecl>("namespace");
  const SourceManager &Sources = *Result.SourceManager;

  if (!locationsInSameFile(Sources, ND->getLocStart(), ND->getRBraceLoc()))
    return;

  // Don't require closing comments for namespaces spanning less than certain
  // number of lines.
  unsigned StartLine = Sources.getSpellingLineNumber(ND->getLocStart());
  unsigned EndLine = Sources.getSpellingLineNumber(ND->getRBraceLoc());
  if (EndLine - StartLine + 1 <= ShortNamespaceLines)
    return;

  // Find next token after the namespace closing brace.
  SourceLocation AfterRBrace = ND->getRBraceLoc().getLocWithOffset(1);
  SourceLocation Loc = AfterRBrace;
  Token Tok;
  // Skip whitespace until we find the next token.
  while (Lexer::getRawToken(Loc, Tok, Sources, Result.Context->getLangOpts())) {
    Loc = Loc.getLocWithOffset(1);
  }
  if (!locationsInSameFile(Sources, ND->getRBraceLoc(), Loc))
    return;

  bool NextTokenIsOnSameLine = Sources.getSpellingLineNumber(Loc) == EndLine;
  // If we insert a line comment before the token in the same line, we need
  // to insert a line break.
  bool NeedLineBreak = NextTokenIsOnSameLine && Tok.isNot(tok::eof);

  SourceRange OldCommentRange(AfterRBrace, AfterRBrace);
  std::string Message = "%0 not terminated with a closing comment";

  // Try to find existing namespace closing comment on the same line.
  if (Tok.is(tok::comment) && NextTokenIsOnSameLine) {
    StringRef Comment(Sources.getCharacterData(Loc), Tok.getLength());
    SmallVector<StringRef, 7> Groups;
    if (NamespaceCommentPattern.match(Comment, &Groups)) {
      StringRef NamespaceNameInComment = Groups.size() > 5 ? Groups[5] : "";
      StringRef Anonymous = Groups.size() > 3 ? Groups[3] : "";

      // Check if the namespace in the comment is the same.
      if ((ND->isAnonymousNamespace() && NamespaceNameInComment.empty()) ||
          (ND->getNameAsString() == NamespaceNameInComment &&
           Anonymous.empty())) {
        // FIXME: Maybe we need a strict mode, where we always fix namespace
        // comments with different format.
        return;
      }

      // Otherwise we need to fix the comment.
      NeedLineBreak = Comment.startswith("/*");
      OldCommentRange =
          SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
      Message =
          (llvm::Twine(
               "%0 ends with a comment that refers to a wrong namespace '") +
           NamespaceNameInComment + "'").str();
    } else if (Comment.startswith("//")) {
      // Assume that this is an unrecognized form of a namespace closing line
      // comment. Replace it.
      NeedLineBreak = false;
      OldCommentRange =
          SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
      Message = "%0 ends with an unrecognized comment";
    }
    // If it's a block comment, just move it to the next line, as it can be
    // multi-line or there may be other tokens behind it.
  }

  std::string NamespaceName =
      ND->isAnonymousNamespace()
          ? "anonymous namespace"
          : ("namespace '" + ND->getNameAsString() + "'");

  diag(AfterRBrace, Message)
      << NamespaceName << FixItHint::CreateReplacement(
                              CharSourceRange::getCharRange(OldCommentRange),
                              std::string(SpacesBeforeComments, ' ') +
                                  getNamespaceComment(ND, NeedLineBreak));
  diag(ND->getLocation(), "%0 starts here", DiagnosticIDs::Note)
      << NamespaceName;
}
Ejemplo n.º 14
0
 SourceLocation IncrementalParser::getLastMemoryBufferEndLoc() const {
   const SourceManager& SM = getCI()->getSourceManager();
   SourceLocation Result = SM.getLocForStartOfFile(m_VirtualFileID);
   return Result.getLocWithOffset(m_MemoryBuffers.size() + 1);
 }
Ejemplo n.º 15
0
  // Add the input to the memory buffer, parse it, and add it to the AST.
  IncrementalParser::EParseResult
  IncrementalParser::ParseInternal(llvm::StringRef input) {
    if (input.empty()) return IncrementalParser::kSuccess;

    Sema& S = getCI()->getSema();

    assert(!(S.getLangOpts().Modules
             && m_Consumer->getTransaction()->getCompilationOpts()
              .CodeGenerationForModule)
           && "CodeGenerationForModule should be removed once modules are available!");

    // Recover resources if we crash before exiting this method.
    llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);

    Preprocessor& PP = m_CI->getPreprocessor();
    if (!PP.getCurrentLexer()) {
       PP.EnterSourceFile(m_CI->getSourceManager().getMainFileID(),
                          0, SourceLocation());
    }
    assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
    PP.enableIncrementalProcessing();

    std::ostringstream source_name;
    source_name << "input_line_" << (m_MemoryBuffers.size() + 1);

    // Create an uninitialized memory buffer, copy code in and append "\n"
    size_t InputSize = input.size(); // don't include trailing 0
    // MemBuffer size should *not* include terminating zero
    llvm::MemoryBuffer* MB
      = llvm::MemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
                                                  source_name.str());
    char* MBStart = const_cast<char*>(MB->getBufferStart());
    memcpy(MBStart, input.data(), InputSize);
    memcpy(MBStart + InputSize, "\n", 2);

    m_MemoryBuffers.push_back(MB);
    SourceManager& SM = getCI()->getSourceManager();

    // Create SourceLocation, which will allow clang to order the overload
    // candidates for example
    SourceLocation NewLoc = SM.getLocForStartOfFile(m_VirtualFileID);
    NewLoc = NewLoc.getLocWithOffset(m_MemoryBuffers.size() + 1);

    // Create FileID for the current buffer
    FileID FID = SM.createFileIDForMemBuffer(m_MemoryBuffers.back(),
                                             SrcMgr::C_User,
                                             /*LoadedID*/0,
                                             /*LoadedOffset*/0, NewLoc);

    PP.EnterSourceFile(FID, /*DirLookup*/0, NewLoc);

    Parser::DeclGroupPtrTy ADecl;

    while (!m_Parser->ParseTopLevelDecl(ADecl)) {
      // If we got a null return and something *was* parsed, ignore it.  This
      // is due to a top-level semicolon, an action override, or a parse error
      // skipping something.
      if (ADecl)
        m_Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
    };

    // Process any TopLevelDecls generated by #pragma weak.
    for (llvm::SmallVector<Decl*,2>::iterator I = S.WeakTopLevelDecls().begin(),
           E = S.WeakTopLevelDecls().end(); I != E; ++I) {
      m_Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
    }

    DiagnosticsEngine& Diag = S.getDiagnostics();
    if (Diag.hasErrorOccurred())
      return IncrementalParser::kFailed;
    else if (Diag.getNumWarnings())
      return IncrementalParser::kSuccessWithWarnings;

    return IncrementalParser::kSuccess;
  }
Ejemplo n.º 16
0
static void format() {
    FileManager Files((FileSystemOptions()));
    DiagnosticsEngine Diagnostics(
        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
        new DiagnosticOptions);
    SourceManager Sources(Diagnostics, Files);
    OwningPtr<MemoryBuffer> Code;
    if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) {
        llvm::errs() << ec.message() << "\n";
        return;
    }
    FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files);
    Lexer Lex(ID, Sources.getBuffer(ID), Sources, getFormattingLangOpts());
    if (Offsets.empty())
        Offsets.push_back(0);
    if (Offsets.size() != Lengths.size() &&
            !(Offsets.size() == 1 && Lengths.empty())) {
        llvm::errs() << "Number of -offset and -length arguments must match.\n";
        return;
    }
    std::vector<CharSourceRange> Ranges;
    for (cl::list<int>::size_type i = 0, e = Offsets.size(); i != e; ++i) {
        SourceLocation Start =
            Sources.getLocForStartOfFile(ID).getLocWithOffset(Offsets[i]);
        SourceLocation End;
        if (i < Lengths.size()) {
            End = Start.getLocWithOffset(Lengths[i]);
        } else {
            End = Sources.getLocForEndOfFile(ID);
        }
        Ranges.push_back(CharSourceRange::getCharRange(Start, End));
    }
    tooling::Replacements Replaces = reformat(getStyle(), Lex, Sources, Ranges);
    if (OutputXML) {
        llvm::outs() << "<?xml version='1.0'?>\n<replacements xml:space='preserve'>\n";
        for (tooling::Replacements::const_iterator I = Replaces.begin(),
                E = Replaces.end();
                I != E; ++I) {
            llvm::outs() << "<replacement "
                         << "offset='" << I->getOffset() << "' "
                         << "length='" << I->getLength() << "'>"
                         << I->getReplacementText() << "</replacement>\n";
        }
        llvm::outs() << "</replacements>\n";
    } else {
        Rewriter Rewrite(Sources, LangOptions());
        tooling::applyAllReplacements(Replaces, Rewrite);
        if (Inplace) {
            if (Replaces.size() == 0)
                return; // Nothing changed, don't touch the file.

            std::string ErrorInfo;
            llvm::raw_fd_ostream FileStream(FileName.c_str(), ErrorInfo,
                                            llvm::raw_fd_ostream::F_Binary);
            if (!ErrorInfo.empty()) {
                llvm::errs() << "Error while writing file: " << ErrorInfo << "\n";
                return;
            }
            Rewrite.getEditBuffer(ID).write(FileStream);
            FileStream.flush();
        } else {
            Rewrite.getEditBuffer(ID).write(outs());
        }
    }
}
Ejemplo n.º 17
0
void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID,
                                             const char *title) {

  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID);
  const char* FileStart = Buf->getBufferStart();
  const char* FileEnd = Buf->getBufferEnd();

  SourceLocation StartLoc = R.getSourceMgr().getLocForStartOfFile(FID);
  SourceLocation EndLoc = StartLoc.getLocWithOffset(FileEnd-FileStart);

  std::string s;
  llvm::raw_string_ostream os(s);
  os << "<!doctype html>\n" // Use HTML 5 doctype
        "<html>\n<head>\n";

  if (title)
    os << "<title>" << html::EscapeText(title) << "</title>\n";

  os << "<style type=\"text/css\">\n"
      " body { color:#000000; background-color:#ffffff }\n"
      " body { font-family:Helvetica, sans-serif; font-size:10pt }\n"
      " h1 { font-size:14pt }\n"
      " .code { border-collapse:collapse; width:100%; }\n"
      " .code { font-family: \"Monospace\", monospace; font-size:10pt }\n"
      " .code { line-height: 1.2em }\n"
      " .comment { color: green; font-style: oblique }\n"
      " .keyword { color: blue }\n"
      " .string_literal { color: red }\n"
      " .directive { color: darkmagenta }\n"
      // Macro expansions.
      " .expansion { display: none; }\n"
      " .macro:hover .expansion { display: block; border: 2px solid #FF0000; "
          "padding: 2px; background-color:#FFF0F0; font-weight: normal; "
          "  -webkit-border-radius:5px;  -webkit-box-shadow:1px 1px 7px #000; "
          "  border-radius:5px;  box-shadow:1px 1px 7px #000; "
          "position: absolute; top: -1em; left:10em; z-index: 1 } \n"
      " .macro { color: darkmagenta; background-color:LemonChiffon;"
             // Macros are position: relative to provide base for expansions.
             " position: relative }\n"
      " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n"
      " .num { text-align:right; font-size:8pt }\n"
      " .num { color:#444444 }\n"
      " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n"
      " .line { white-space: pre }\n"
      " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n"
      " .msg { box-shadow:1px 1px 7px #000 }\n"
      " .msg { -webkit-border-radius:5px }\n"
      " .msg { border-radius:5px }\n"
      " .msg { font-family:Helvetica, sans-serif; font-size:8pt }\n"
      " .msg { float:left }\n"
      " .msg { padding:0.25em 1ex 0.25em 1ex }\n"
      " .msg { margin-top:10px; margin-bottom:10px }\n"
      " .msg { font-weight:bold }\n"
      " .msg { max-width:60em; word-wrap: break-word; white-space: pre-wrap }\n"
      " .msgT { padding:0x; spacing:0x }\n"
      " .msgEvent { background-color:#fff8b4; color:#000000 }\n"
      " .msgControl { background-color:#bbbbbb; color:#000000 }\n"
      " .mrange { background-color:#dfddf3 }\n"
      " .mrange { border-bottom:1px solid #6F9DBE }\n"
      " .PathIndex { font-weight: bold; padding:0px 5px; "
        "margin-right:5px; }\n"
      " .PathIndex { -webkit-border-radius:8px }\n"
      " .PathIndex { border-radius:8px }\n"
      " .PathIndexEvent { background-color:#bfba87 }\n"
      " .PathIndexControl { background-color:#8c8c8c }\n"
      " .PathNav a { text-decoration:none; font-size: larger }\n"
      " .CodeInsertionHint { font-weight: bold; background-color: #10dd10 }\n"
      " .CodeRemovalHint { background-color:#de1010 }\n"
      " .CodeRemovalHint { border-bottom:1px solid #6F9DBE }\n"
      " table.simpletable {\n"
      "   padding: 5px;\n"
      "   font-size:12pt;\n"
      "   margin:20px;\n"
      "   border-collapse: collapse; border-spacing: 0px;\n"
      " }\n"
      " td.rowname {\n"
      "   text-align:right; font-weight:bold; color:#444444;\n"
      "   padding-right:2ex; }\n"
      "</style>\n</head>\n<body>";

  // Generate header
  R.InsertTextBefore(StartLoc, os.str());
  // Generate footer

  R.InsertTextAfter(EndLoc, "</body></html>\n");
}
Ejemplo n.º 18
0
/// ParseDirective - Go through the comment and see if it indicates expected
/// diagnostics. If so, then put them in the appropriate directive list.
///
/// Returns true if any valid directives were found.
static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
                           Preprocessor *PP, SourceLocation Pos,
                           VerifyDiagnosticConsumer::DirectiveStatus &Status,
                           VerifyDiagnosticConsumer::MarkerTracker &Markers) {
  DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics();

  // First, scan the comment looking for markers.
  for (ParseHelper PH(S); !PH.Done();) {
    if (!PH.Search("#", true))
      break;
    PH.C = PH.P;
    if (!PH.NextMarker()) {
      PH.Next("#");
      PH.Advance();
      continue;
    }
    PH.Advance();
    Markers.addMarker(PH.Match(), Pos);
  }

  // A single comment may contain multiple directives.
  bool FoundDirective = false;
  for (ParseHelper PH(S); !PH.Done();) {
    // Search for the initial directive token.
    // If one prefix, save time by searching only for its directives.
    // Otherwise, search for any potential directive token and check it later.
    const auto &Prefixes = Diags.getDiagnosticOptions().VerifyPrefixes;
    if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(), true, true)
                               : PH.Search("", true, true)))
      break;

    StringRef DToken = PH.Match();
    PH.Advance();

    // Default directive kind.
    UnattachedDirective D;
    const char *KindStr = "string";

    // Parse the initial directive token in reverse so we can easily determine
    // its exact actual prefix.  If we were to parse it from the front instead,
    // it would be harder to determine where the prefix ends because there
    // might be multiple matching -verify prefixes because some might prefix
    // others.

    // Regex in initial directive token: -re
    if (DToken.endswith("-re")) {
      D.RegexKind = true;
      KindStr = "regex";
      DToken = DToken.substr(0, DToken.size()-3);
    }

    // Type in initial directive token: -{error|warning|note|no-diagnostics}
    bool NoDiag = false;
    StringRef DType;
    if (DToken.endswith(DType="-error"))
      D.DL = ED ? &ED->Errors : nullptr;
    else if (DToken.endswith(DType="-warning"))
      D.DL = ED ? &ED->Warnings : nullptr;
    else if (DToken.endswith(DType="-remark"))
      D.DL = ED ? &ED->Remarks : nullptr;
    else if (DToken.endswith(DType="-note"))
      D.DL = ED ? &ED->Notes : nullptr;
    else if (DToken.endswith(DType="-no-diagnostics")) {
      NoDiag = true;
      if (D.RegexKind)
        continue;
    }
    else
      continue;
    DToken = DToken.substr(0, DToken.size()-DType.size());

    // What's left in DToken is the actual prefix.  That might not be a -verify
    // prefix even if there is only one -verify prefix (for example, the full
    // DToken is foo-bar-warning, but foo is the only -verify prefix).
    if (!std::binary_search(Prefixes.begin(), Prefixes.end(), DToken))
      continue;

    if (NoDiag) {
      if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
        Diags.Report(Pos, diag::err_verify_invalid_no_diags)
          << /*IsExpectedNoDiagnostics=*/true;
      else
        Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
      continue;
    }
    if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
      Diags.Report(Pos, diag::err_verify_invalid_no_diags)
        << /*IsExpectedNoDiagnostics=*/false;
      continue;
    }
    Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives;

    // If a directive has been found but we're not interested
    // in storing the directive information, return now.
    if (!D.DL)
      return true;

    // Next optional token: @
    SourceLocation ExpectedLoc;
    StringRef Marker;
    bool MatchAnyLine = false;
    if (!PH.Next("@")) {
      ExpectedLoc = Pos;
    } else {
      PH.Advance();
      unsigned Line = 0;
      bool FoundPlus = PH.Next("+");
      if (FoundPlus || PH.Next("-")) {
        // Relative to current line.
        PH.Advance();
        bool Invalid = false;
        unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid);
        if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
          if (FoundPlus) ExpectedLine += Line;
          else ExpectedLine -= Line;
          ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1);
        }
      } else if (PH.Next(Line)) {
        // Absolute line number.
        if (Line > 0)
          ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1);
      } else if (PH.NextMarker()) {
        Marker = PH.Match();
      } else if (PP && PH.Search(":")) {
        // Specific source file.
        StringRef Filename(PH.C, PH.P-PH.C);
        PH.Advance();

        // Lookup file via Preprocessor, like a #include.
        const DirectoryLookup *CurDir;
        const FileEntry *FE =
            PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
                           nullptr, nullptr, nullptr, nullptr, nullptr);
        if (!FE) {
          Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                       diag::err_verify_missing_file) << Filename << KindStr;
          continue;
        }

        if (SM.translateFile(FE).isInvalid())
          SM.createFileID(FE, Pos, SrcMgr::C_User);

        if (PH.Next(Line) && Line > 0)
          ExpectedLoc = SM.translateFileLineCol(FE, Line, 1);
        else if (PH.Next("*")) {
          MatchAnyLine = true;
          ExpectedLoc = SM.translateFileLineCol(FE, 1, 1);
        }
      } else if (PH.Next("*")) {
        MatchAnyLine = true;
        ExpectedLoc = SourceLocation();
      }

      if (ExpectedLoc.isInvalid() && !MatchAnyLine && Marker.empty()) {
        Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                     diag::err_verify_missing_line) << KindStr;
        continue;
      }
      PH.Advance();
    }

    // Skip optional whitespace.
    PH.SkipWhitespace();

    // Next optional token: positive integer or a '+'.
    if (PH.Next(D.Min)) {
      PH.Advance();
      // A positive integer can be followed by a '+' meaning min
      // or more, or by a '-' meaning a range from min to max.
      if (PH.Next("+")) {
        D.Max = Directive::MaxCount;
        PH.Advance();
      } else if (PH.Next("-")) {
        PH.Advance();
        if (!PH.Next(D.Max) || D.Max < D.Min) {
          Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                       diag::err_verify_invalid_range) << KindStr;
          continue;
        }
        PH.Advance();
      } else {
        D.Max = D.Min;
      }
    } else if (PH.Next("+")) {
      // '+' on its own means "1 or more".
      D.Max = Directive::MaxCount;
      PH.Advance();
    }

    // Skip optional whitespace.
    PH.SkipWhitespace();

    // Next token: {{
    if (!PH.Next("{{")) {
      Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                   diag::err_verify_missing_start) << KindStr;
      continue;
    }
    PH.Advance();
    const char* const ContentBegin = PH.C; // mark content begin
    // Search for token: }}
    if (!PH.SearchClosingBrace("{{", "}}")) {
      Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                   diag::err_verify_missing_end) << KindStr;
      continue;
    }
    const char* const ContentEnd = PH.P; // mark content end
    PH.Advance();

    D.DirectivePos = Pos;
    D.ContentBegin = Pos.getLocWithOffset(ContentBegin - PH.Begin);

    // Build directive text; convert \n to newlines.
    StringRef NewlineStr = "\\n";
    StringRef Content(ContentBegin, ContentEnd-ContentBegin);
    size_t CPos = 0;
    size_t FPos;
    while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
      D.Text += Content.substr(CPos, FPos-CPos);
      D.Text += '\n';
      CPos = FPos + NewlineStr.size();
    }
    if (D.Text.empty())
      D.Text.assign(ContentBegin, ContentEnd);

    // Check that regex directives contain at least one regex.
    if (D.RegexKind && D.Text.find("{{") == StringRef::npos) {
      Diags.Report(D.ContentBegin, diag::err_verify_missing_regex) << D.Text;
      return false;
    }

    if (Marker.empty())
      attachDirective(Diags, D, ExpectedLoc, MatchAnyLine);
    else
      Markers.addDirective(Marker, D);
    FoundDirective = true;
  }

  return FoundDirective;
}
Ejemplo n.º 19
0
/// AvoidConcat - If printing PrevTok immediately followed by Tok would cause
/// the two individual tokens to be lexed as a single token, return true
/// (which causes a space to be printed between them).  This allows the output
/// of -E mode to be lexed to the same token stream as lexing the input
/// directly would.
///
/// This code must conservatively return true if it doesn't want to be 100%
/// accurate.  This will cause the output to include extra space characters,
/// but the resulting output won't have incorrect concatenations going on.
/// Examples include "..", which we print with a space between, because we
/// don't want to track enough to tell "x.." from "...".
bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
                                     const Token &PrevTok,
                                     const Token &Tok) const {
  // First, check to see if the tokens were directly adjacent in the original
  // source.  If they were, it must be okay to stick them together: if there
  // were an issue, the tokens would have been lexed differently.
  SourceManager &SM = PP.getSourceManager();
  SourceLocation PrevSpellLoc = SM.getSpellingLoc(PrevTok.getLocation());
  SourceLocation SpellLoc = SM.getSpellingLoc(Tok.getLocation());
  if (PrevSpellLoc.getLocWithOffset(PrevTok.getLength()) == SpellLoc)
    return false;

  tok::TokenKind PrevKind = PrevTok.getKind();
  if (!PrevTok.isAnnotation() && PrevTok.getIdentifierInfo())
    PrevKind = tok::identifier; // Language keyword or named operator.

  // Look up information on when we should avoid concatenation with prevtok.
  unsigned ConcatInfo = TokenInfo[PrevKind];

  // If prevtok never causes a problem for anything after it, return quickly.
  if (ConcatInfo == 0) return false;

  if (ConcatInfo & aci_avoid_equal) {
    // If the next token is '=' or '==', avoid concatenation.
    if (Tok.isOneOf(tok::equal, tok::equalequal))
      return true;
    ConcatInfo &= ~aci_avoid_equal;
  }
  if (Tok.isAnnotation()) {
    // Modules annotation can show up when generated automatically for includes.
    assert(Tok.isOneOf(tok::annot_module_include, tok::annot_module_begin,
                       tok::annot_module_end) &&
           "unexpected annotation in AvoidConcat");
    ConcatInfo = 0;
  }

  if (ConcatInfo == 0)
    return false;

  // Basic algorithm: we look at the first character of the second token, and
  // determine whether it, if appended to the first token, would form (or
  // would contribute) to a larger token if concatenated.
  char FirstChar = 0;
  if (ConcatInfo & aci_custom) {
    // If the token does not need to know the first character, don't get it.
  } else {
    FirstChar = GetFirstChar(PP, Tok);
  }

  switch (PrevKind) {
  default:
    llvm_unreachable("InitAvoidConcatTokenInfo built wrong");

  case tok::raw_identifier:
    llvm_unreachable("tok::raw_identifier in non-raw lexing mode!");

  case tok::string_literal:
  case tok::wide_string_literal:
  case tok::utf8_string_literal:
  case tok::utf16_string_literal:
  case tok::utf32_string_literal:
  case tok::char_constant:
  case tok::wide_char_constant:
  case tok::utf8_char_constant:
  case tok::utf16_char_constant:
  case tok::utf32_char_constant:
    if (!PP.getLangOpts().CPlusPlus11)
      return false;

    // In C++11, a string or character literal followed by an identifier is a
    // single token.
    if (Tok.getIdentifierInfo())
      return true;

    // A ud-suffix is an identifier. If the previous token ends with one, treat
    // it as an identifier.
    if (!PrevTok.hasUDSuffix())
      return false;
    // FALL THROUGH.
  case tok::identifier:   // id+id or id+number or id+L"foo".
    // id+'.'... will not append.
    if (Tok.is(tok::numeric_constant))
      return GetFirstChar(PP, Tok) != '.';

    if (Tok.getIdentifierInfo() ||
        Tok.isOneOf(tok::wide_string_literal, tok::utf8_string_literal,
                    tok::utf16_string_literal, tok::utf32_string_literal,
                    tok::wide_char_constant, tok::utf8_char_constant,
                    tok::utf16_char_constant, tok::utf32_char_constant))
      return true;

    // If this isn't identifier + string, we're done.
    if (Tok.isNot(tok::char_constant) && Tok.isNot(tok::string_literal))
      return false;

    // Otherwise, this is a narrow character or string.  If the *identifier*
    // is a literal 'L', 'u8', 'u' or 'U', avoid pasting L "foo" -> L"foo".
    return IsIdentifierStringPrefix(PrevTok);

  case tok::numeric_constant:
    return isPreprocessingNumberBody(FirstChar) ||
           FirstChar == '+' || FirstChar == '-';
  case tok::period:          // ..., .*, .1234
    return (FirstChar == '.' && PrevPrevTok.is(tok::period)) ||
           isDigit(FirstChar) ||
           (PP.getLangOpts().CPlusPlus && FirstChar == '*');
  case tok::amp:             // &&
    return FirstChar == '&';
  case tok::plus:            // ++
    return FirstChar == '+';
  case tok::minus:           // --, ->, ->*
    return FirstChar == '-' || FirstChar == '>';
  case tok::slash:           //, /*, //
    return FirstChar == '*' || FirstChar == '/';
  case tok::less:            // <<, <<=, <:, <%
    return FirstChar == '<' || FirstChar == ':' || FirstChar == '%';
  case tok::greater:         // >>, >>=
    return FirstChar == '>';
  case tok::pipe:            // ||
    return FirstChar == '|';
  case tok::percent:         // %>, %:
    return FirstChar == '>' || FirstChar == ':';
  case tok::colon:           // ::, :>
    return FirstChar == '>' ||
    (PP.getLangOpts().CPlusPlus && FirstChar == ':');
  case tok::hash:            // ##, #@, %:%:
    return FirstChar == '#' || FirstChar == '@' || FirstChar == '%';
  case tok::arrow:           // ->*
    return PP.getLangOpts().CPlusPlus && FirstChar == '*';
  }
}
Ejemplo n.º 20
0
    virtual void run(const MatchFinder::MatchResult &Result){
        const BinaryOperator* BO = Result.Nodes.getNodeAs<BinaryOperator>("malloc");
        #ifdef DEBUG
        llvm::errs()<<"----BinaryOperator(malloc) find----\n";
        #endif
        if(!BO)   return ;
        const SourceManager *SM = Result.SourceManager;
        SourceLocation locEnd = BO->getLocEnd();
        checkPoint cp;
      
	
		//得到插装位置,找到mallocVarMatcher之前对应匹配到的信息(其实可以不用MallocVarMatcher,MallocVarMatcher只能匹配到纯粹的指针(不带*的))
        std::string str_locEnd = locEnd.printToString(*SM);
        loc_strToint(cp.row,cp.col,str_locEnd.c_str());
        bool findFlag = false;
        int findI;
        
        #ifdef DEBUG
        llvm::errs() <<"binary loc:" <<"|"<<cp.row<<"|"<<cp.col<<"\n";
        #endif
        
        for(unsigned i=0;i<cpVec.size();++i){
            if(cpVec[i].row == cp.row){
                    findFlag = true;
                    findI = i;
                    break;
                }
        }
		//左子树得到的 = 的左边
        Expr * lhs = BO->getLHS();
        cp.name = rewrite.ConvertToString((Stmt*)lhs);
        
        QualType qt = lhs->getType();
        #ifdef DEBUG
        llvm::errs()<<"lhs cp.name :"<<cp.name<<"\n";
        llvm::errs()<<"lhs type :"<<qt.getAsString()<<"\n";
        lhs->dump();
        #endif
        
		//找到的话直接用
        if(findFlag){        
            const NamedDecl *ND = ((DeclRefExpr*)lhs)->getFoundDecl();
            std::string str_decl = ND->getNameAsString();
            cp.declName = str_decl;
            SourceLocation declLocStart = ND->getLocStart();
            std::string str_declLocStart = declLocStart.printToString(*SM);
            loc_strToint(cp.declRow,cp.declCol,str_declLocStart.c_str());
        
        }else{//没找到的话,添加进来
            cp.declName = cp.name;
            cp.declRow = cp.row;
            cp.declCol = cp.col;
        }
        
		//string + 不支持int类型,所以先换成char*
        char buf[4][32];
        sprintf(buf[0],"%d",cp.row);
        sprintf(buf[1],"%d",cp.col);
        sprintf(buf[2],"%d",cp.declRow);
        sprintf(buf[3],"%d",cp.declCol);  
                                     
        //将程序运行时的指针值存下来 %x                                     
        std::string str_insert = 
        "\n{\n\tFILE *fp = fopen(\"" + checkDataFileName +"\",\"a\");\n"
        "\tif(fp == NULL){\n" +
        "\t\tprintf(\"fail to open file " + checkDataFileName + "!\\n\");\n" +
        "\t\texit(-1);\n" + 
        "\t}\n" + 
        
        //"\tfprintf(fp,\"m " + cp.name + " " + buf[0] + " " + buf[1] + " " + cp.declName + " " + buf[2] + " " + buf[3] + " %x \\n\"," + cp.name + ");\n" +
        "\tfprintf(fp,\"m " + cp.name + " " + buf[0] + " " + buf[1] + " %x \\n\"," + cp.name + ");\n" +
        "\tfclose(fp);\n\n" +
        "\tint fd=open(FIFO_SERVER,O_WRONLY |O_NONBLOCK,0);\n" + 
        "\tif(fd==-1){perror(\"open\");exit(1);}\n" + 
        "\tchar w_buf[100];\n" + 
        "\tsprintf(w_buf,\"m "+ cp.name + " " + buf[0] + " " + buf[1] + " %x \\n\"," + cp.name + ");\n" + 
        "\tif(write(fd,w_buf,100)==-1){\n" + 
        "\t\tif(errno==EAGAIN)\n" + 
        "\t\t\tprintf(\"The FIFO has not been read yet.Please try later\\n\");\n" + 
        "\t}\n" + 
        "\telse\n" + 
        "\t\tprintf(\"write %s to the FIFO\\n\",w_buf);\n" +
        "\tsleep(1);\n" + 
        "\tclose(fd);\n" + 
        "}\n";
        
        
        
        //llvm::errs() << "-----\n"<<str_insert<<"\n----\n";
		//找位置插装
        int locOffset = 2;
        SourceLocation SL_locWithOffset = locEnd.getLocWithOffset(locOffset);
        rewrite.InsertText(SL_locWithOffset,str_insert.c_str(),true,true); 
        
		if(!findFlag){        
            cpVec.push_back(cp);
        }

        #ifdef DEBUG
        llvm::errs()<<"----BinaryOperator(malloc) end----\n";
        #endif
    }
  bool VisitFunctionDecl(FunctionDecl *f) {
    // Only function definitions (with bodies), not declarations.
    if (f->hasBody()) {
      Stmt *FuncBody = f->getBody();

      // Type name as string
      QualType QT = f->getReturnType();
      std::string TypeStr = QT.getAsString();

      // Function name
      DeclarationName DeclName = f->getNameInfo().getName();
      std::string FuncName = DeclName.getAsString();

      // Add comment before
      std::stringstream SSBefore;
      SSBefore << "// Begin function " << FuncName << " returning " << TypeStr
               << "\n";
      SourceLocation ST = f->getSourceRange().getBegin();
      TheRewriter.InsertText(ST, SSBefore.str(), true, true);

      // And after
      std::stringstream SSAfter;
      SSAfter << "\n// End function " << FuncName;
      ST = FuncBody->getLocEnd().getLocWithOffset(1);
      TheRewriter.InsertText(ST, SSAfter.str(), true, true);
      
      int forCounter=0;
    Stmt::child_iterator CI, CE = FuncBody->child_end();
    for (CI = FuncBody->child_begin(); CI != CE; ++CI) {
      if (*CI != 0) {
        if (isa<ForStmt>(*CI)) 
        {
            forCounter++;
            std::stringstream MarkerBefore;
            std::stringstream MarkerAfter;
            MarkerBefore<<"\nMCPROF_ZONE_ENTER(" << forCounter << ");\n";
            MarkerAfter<<"\nMCPROF_ZONE_EXIT(" << forCounter << ");\n";
            ForStmt *For = cast<ForStmt>(*CI);
            SourceLocation ST = For->getLocStart();
            TheRewriter.InsertText(ST, MarkerBefore.str(), true, false);
            Stmt *ForBody = For->getBody();
            SourceLocation END = ForBody->getLocEnd();
            int offset = Lexer::MeasureTokenLength(END,
                                        TheRewriter.getSourceMgr(),
                                        TheRewriter.getLangOpts()) + 1;

            SourceLocation END1 = END.getLocWithOffset(offset);
            TheRewriter.InsertText(END1, MarkerAfter.str(), true, false);

//          llvm::errs() << " Detected for loop number " << forCounter 
//                       << " in function " << FuncName << "\n";

//             InstrumentStmt(ForBody);

//             Stmt *ForBody = CI->getBody();
//             SourceLocation ST = CI->getLocStart();
//             char *b = sourceManager->getCharacterData(_b)
//             llvm::errs()  << ST << " is location \n";
        }
      }
    }

    }

    return true;
  }
Ejemplo n.º 22
0
  Interpreter::CompilationResult
  Interpreter::EvaluateInternal(const std::string& input,
                                const CompilationOptions& CO,
                                Value* V, /* = 0 */
                                Transaction** T /* = 0 */) {
    StateDebuggerRAII stateDebugger(this);

    // Wrap the expression
    std::string WrapperName;
    std::string Wrapper = input;
    WrapInput(Wrapper, WrapperName);

    // Disable warnings which doesn't make sense when using the prompt
    // This gets reset with the clang::Diagnostics().Reset(/*soft*/=false)
    // using clang's API we simulate:
    // #pragma warning push
    // #pragma warning ignore ...
    // #pragma warning ignore ...
    // #pragma warning pop
    SourceLocation Loc = getNextAvailableLoc();
    DiagnosticsEngine& Diags = getCI()->getDiagnostics();
    Diags.pushMappings(Loc);
    // The source locations of #pragma warning ignore must be greater than
    // the ones from #pragma push
    Diags.setSeverity(clang::diag::warn_unused_expr,
                      clang::diag::Severity::Ignored, SourceLocation());
    Diags.setSeverity(clang::diag::warn_unused_call,
                      clang::diag::Severity::Ignored, SourceLocation());
    Diags.setSeverity(clang::diag::warn_unused_comparison,
                      clang::diag::Severity::Ignored, SourceLocation());
    Diags.setSeverity(clang::diag::ext_return_has_expr,
                      clang::diag::Severity::Ignored, SourceLocation());
    if (Transaction* lastT = m_IncrParser->Compile(Wrapper, CO)) {
      Loc = m_IncrParser->getLastMemoryBufferEndLoc().getLocWithOffset(1);
      // if the location was the same we are in recursive calls and to avoid an
      // assert in clang we should increment by a value.
      if (SourceLocation::getFromRawEncoding(m_LastCustomPragmaDiagPopPoint)
          == Loc)
        // Nested #pragma pop-s must be on different source locations.
        Loc = Loc.getLocWithOffset(1);
      m_LastCustomPragmaDiagPopPoint = Loc.getRawEncoding();

      Diags.popMappings(Loc);
      assert((lastT->getState() == Transaction::kCommitted
              || lastT->getState() == Transaction::kRolledBack)
             && "Not committed?");
      if (lastT->getIssuedDiags() != Transaction::kErrors) {
        Value resultV;
        if (!V)
          V = &resultV;
        if (!lastT->getWrapperFD()) // no wrapper to run
          return Interpreter::kSuccess;
        else if (RunFunction(lastT->getWrapperFD(), V) < kExeFirstError){
          if (lastT->getCompilationOpts().ValuePrinting
              != CompilationOptions::VPDisabled
              && V->isValid()
              // the !V->needsManagedAllocation() case is handled by
              // dumpIfNoStorage.
              && V->needsManagedAllocation())
            V->dump();
          return Interpreter::kSuccess;
        }
      }
      if (V)
        *V = Value();

      return Interpreter::kFailure;
    }
    Diags.popMappings(Loc.getLocWithOffset(1));
    return Interpreter::kSuccess;
  }
void NamespaceCommentCheck::check(const MatchFinder::MatchResult &Result) {
  const NamespaceDecl *ND = Result.Nodes.getNodeAs<NamespaceDecl>("namespace");
  const SourceManager &Sources = *Result.SourceManager;

  if (!locationsInSameFile(Sources, ND->getLocStart(), ND->getRBraceLoc()))
    return;

  // Don't require closing comments for namespaces spanning less than certain
  // number of lines.
  unsigned StartLine = Sources.getSpellingLineNumber(ND->getLocStart());
  unsigned EndLine = Sources.getSpellingLineNumber(ND->getRBraceLoc());
  if (EndLine - StartLine + 1 <= ShortNamespaceLines)
    return;

  // Find next token after the namespace closing brace.
  SourceLocation AfterRBrace = ND->getRBraceLoc().getLocWithOffset(1);
  SourceLocation Loc = AfterRBrace;
  Token Tok;
  // Skip whitespace until we find the next token.
  while (Lexer::getRawToken(Loc, Tok, Sources, Result.Context->getLangOpts())) {
    Loc = Loc.getLocWithOffset(1);
  }
  if (!locationsInSameFile(Sources, ND->getRBraceLoc(), Loc))
    return;

  bool NextTokenIsOnSameLine = Sources.getSpellingLineNumber(Loc) == EndLine;
  // If we insert a line comment before the token in the same line, we need
  // to insert a line break.
  bool NeedLineBreak = NextTokenIsOnSameLine && Tok.isNot(tok::eof);

  // Try to find existing namespace closing comment on the same line.
  if (Tok.is(tok::comment) && NextTokenIsOnSameLine) {
    StringRef Comment(Sources.getCharacterData(Loc), Tok.getLength());
    SmallVector<StringRef, 6> Groups;
    if (NamespaceCommentPattern.match(Comment, &Groups)) {
      StringRef NamespaceNameInComment = Groups.size() >= 6 ? Groups[5] : "";

      // Check if the namespace in the comment is the same.
      if ((ND->isAnonymousNamespace() && NamespaceNameInComment.empty()) ||
          ND->getNameAsString() == NamespaceNameInComment) {
        // FIXME: Maybe we need a strict mode, where we always fix namespace
        // comments with different format.
        return;
      }

      // Otherwise we need to fix the comment.
      NeedLineBreak = Comment.startswith("/*");
      CharSourceRange OldCommentRange = CharSourceRange::getCharRange(
          SourceRange(Loc, Loc.getLocWithOffset(Tok.getLength())));
      diag(Loc, "namespace closing comment refers to a wrong namespace '%0'")
          << NamespaceNameInComment
          << FixItHint::CreateReplacement(
                 OldCommentRange, getNamespaceComment(ND, NeedLineBreak));
      return;
    }

    // This is not a recognized form of a namespace closing comment.
    // Leave line comment on the same line. Move block comment to the next line,
    // as it can be multi-line or there may be other tokens behind it.
    if (Comment.startswith("//"))
      NeedLineBreak = false;
  }

  diag(ND->getLocation(), "namespace not terminated with a closing comment")
      << FixItHint::CreateInsertion(AfterRBrace,
                                    std::string(SpacesBeforeComments, ' ') +
                                        getNamespaceComment(ND, NeedLineBreak));
}
Ejemplo n.º 24
0
bool RewriteUtils::removeParamFromFuncDecl(const ParmVarDecl *PV,
                                           unsigned int NumParams,
                                           int ParamPos)
{
  SourceRange ParamLocRange = PV->getSourceRange();
  int RangeSize;
 
  SourceLocation StartLoc = ParamLocRange.getBegin();
  if (StartLoc.isInvalid()) {
    StartLoc = ParamLocRange.getEnd();
    RangeSize = PV->getNameAsString().size();
  }
  else {
    RangeSize = TheRewriter->getRangeSize(ParamLocRange);
    if (RangeSize == -1)
      return false;
  }

  // The param is the only parameter of the function declaration.
  // Replace it with void
  if ((ParamPos == 0) && (NumParams == 1)) {
    // Note that ')' is included in ParamLocRange for unnamed parameter
    if (PV->getDeclName())
      return !(TheRewriter->ReplaceText(StartLoc,
                                        RangeSize, "void"));
    else
      return !(TheRewriter->ReplaceText(StartLoc,
                                        RangeSize - 1, "void"));
  }

  // The param is the last parameter
  if (ParamPos == static_cast<int>(NumParams - 1)) {
    int Offset = 0;
    const char *StartBuf = 
      SrcManager->getCharacterData(StartLoc);

    TransAssert(StartBuf && "Invalid start buffer!");
    while (*StartBuf != ',') {
      StartBuf--;
      Offset--;
    }

    SourceLocation NewStartLoc = StartLoc.getLocWithOffset(Offset);

    // Note that ')' is included in ParamLocRange for unnamed parameter
    // Also note that C++ supports unnamed parameters with default values,
    // i.e., foo(int x, int = 0);
    // PV->hasDefaultArg() is to handle this special case
    if (PV->getDeclName() || PV->hasDefaultArg())
      return !(TheRewriter->RemoveText(NewStartLoc, 
                                       RangeSize - Offset));
    else
      return !(TheRewriter->RemoveText(NewStartLoc, 
                                       RangeSize - Offset - 1));
  }
 
  // Clang gives inconsistent RangeSize for named and unnamed parameter decls.
  // For example, for the first parameter, 
  //   foo(int, int);  -- RangeSize is 4, i.e., "," is counted
  //   foo(int x, int);  -- RangeSize is 5, i.e., ","is not included
  if (PV->getDeclName()) {
    // We cannot use the code below:
    //   SourceLocation EndLoc = ParamLocRange.getEnd();
    //   const char *EndBuf = 
    //     ConsumerInstance->SrcManager->getCharacterData(EndLoc);
    // Because getEnd() returns the start of the last token if this
    // is a token range. For example, in the above example, 
    // getEnd() points to the start of "x"
    // See the comments on getRangeSize in clang/lib/Rewriter/Rewriter.cpp
    int NewRangeSize = 0;
    const char *StartBuf = 
      SrcManager->getCharacterData(StartLoc);

    while (NewRangeSize < RangeSize) {
      StartBuf++;
      NewRangeSize++;
    }

    TransAssert(StartBuf && "Invalid start buffer!");
    while (*StartBuf != ',') {
      StartBuf++;
      NewRangeSize++;
    }

    return !(TheRewriter->RemoveText(StartLoc, 
                                     NewRangeSize + 1));
  }
  else {
    return !(TheRewriter->RemoveText(StartLoc, RangeSize));
  }
}