SourceLocation
ClangAsmParserCallback::translateLocation(const llvm::SourceMgr &LSM,
                                          llvm::SMLoc SMLoc) {
  // Compute an offset into the inline asm buffer.
  // FIXME: This isn't right if .macro is involved (but hopefully, no
  // real-world code does that).
  const llvm::MemoryBuffer *LBuf =
      LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
  unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();

  // Figure out which token that offset points into.
  const unsigned *TokOffsetPtr =
      std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
  unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
  unsigned TokOffset = *TokOffsetPtr;

  // If we come up with an answer which seems sane, use it; otherwise,
  // just point at the __asm keyword.
  // FIXME: Assert the answer is sane once we handle .macro correctly.
  SourceLocation Loc = AsmLoc;
  if (TokIndex < AsmToks.size()) {
    const Token &Tok = AsmToks[TokIndex];
    Loc = Tok.getLocation();
    Loc = Loc.getLocWithOffset(Offset - TokOffset);
  }
  return Loc;
}
Beispiel #2
0
/// \brief Takes a list of diagnostics that were expected to have been generated
/// but were not and produces a diagnostic to the user from this.
static unsigned PrintExpected(DiagnosticsEngine &Diags, llvm::SourceMgr &SourceMgr,
                              DirectiveList &DL, const char *Kind) {
  if (DL.empty())
    return 0;

  SmallString<256> Fmt;
  llvm::raw_svector_ostream OS(Fmt);
  for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
    Directive &D = **I;
    OS << "\n  Line " << SourceMgr.getLineAndColumn(D.DiagnosticLoc).first;
    if (D.DirectiveLoc != D.DiagnosticLoc) {
      int BufID = SourceMgr.FindBufferContainingLoc(D.DirectiveLoc);
      OS << " (directive at "
         << SourceMgr.getMemoryBuffer(BufID)->getBufferIdentifier()
         << SourceMgr.getLineAndColumn(D.DirectiveLoc).first << ")";
    }
    OS << ": " << D.Text;
  }

  Diags.Report(SourceLocation(), diag::verify_inconsistent_diags)
    << Kind << /*Unexpected=*/false << OS.str();
  return DL.size();
}
/// \brief Determine whether two source locations come from the same file.
static bool IsFromSameFile(const llvm::SourceMgr &SM, SourceLocation DirectiveLoc,
                           SourceLocation  DiagnosticLoc) {
  return SM.FindBufferContainingLoc(DirectiveLoc) ==
     SM.FindBufferContainingLoc(DiagnosticLoc);
  return true;
}
/// 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, const llvm::SourceMgr &SM,
                           Lexer *PP, const SourceLocation& Pos,
                           VerifyDiagnosticConsumer::DirectiveStatus &Status) {
  DiagnosticsEngine &Diags = PP->getDiagnostics();

  // 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.FindLineNumber(Pos);
        if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
          if (FoundPlus) ExpectedLine += Line;
          else ExpectedLine -= Line;
          ExpectedLoc = translateLine(SM,SM.FindBufferContainingLoc(Pos), ExpectedLine);
        }
      } else if (PH.Next(Line)) {
        // Absolute line number.
        if (Line > 0)
          ExpectedLoc = translateLine(SM,SM.FindBufferContainingLoc(Pos), Line);
      }

      if (!ExpectedLoc.isValid()) {
        Diags.Report(getLocWithOffset(Pos,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(getLocWithOffset(Pos,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(getLocWithOffset(Pos,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(getLocWithOffset(Pos,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(getLocWithOffset(Pos,ContentBegin-PH.Begin),
                   diag::err_verify_invalid_content)
        << KindStr << Error;
    }
  }

  return FoundDirective;
}