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; }
/// \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; }