SourceLoc ClangDiagnosticConsumer::resolveSourceLocation( const clang::SourceManager &clangSrcMgr, clang::SourceLocation clangLoc) { SourceManager &swiftSrcMgr = ImporterImpl.SwiftContext.SourceMgr; SourceLoc loc; clangLoc = clangSrcMgr.getFileLoc(clangLoc); auto decomposedLoc = clangSrcMgr.getDecomposedLoc(clangLoc); if (decomposedLoc.first.isInvalid()) return loc; auto buffer = clangSrcMgr.getBuffer(decomposedLoc.first); unsigned mirrorID; auto mirrorIter = mirroredBuffers.find(buffer); if (mirrorIter != mirroredBuffers.end()) { mirrorID = mirrorIter->second; } else { std::unique_ptr<llvm::MemoryBuffer> mirrorBuffer{ llvm::MemoryBuffer::getMemBuffer(buffer->getBuffer(), buffer->getBufferIdentifier(), /*nullTerminated=*/true) }; mirrorID = swiftSrcMgr.addNewSourceBuffer(std::move(mirrorBuffer)); mirroredBuffers[buffer] = mirrorID; } loc = swiftSrcMgr.getLocForOffset(mirrorID, decomposedLoc.second); auto presumedLoc = clangSrcMgr.getPresumedLoc(clangLoc); if (!presumedLoc.getFilename()) return loc; if (presumedLoc.getLine() == 0) return SourceLoc(); unsigned bufferLineNumber = clangSrcMgr.getLineNumber(decomposedLoc.first, decomposedLoc.second); StringRef presumedFile = presumedLoc.getFilename(); SourceLoc startOfLine = loc.getAdvancedLoc(-presumedLoc.getColumn() + 1); bool isNewVirtualFile = swiftSrcMgr.openVirtualFile(startOfLine, presumedFile, presumedLoc.getLine() - bufferLineNumber); if (isNewVirtualFile) { SourceLoc endOfLine = findEndOfLine(swiftSrcMgr, loc, mirrorID); swiftSrcMgr.closeVirtualFile(endOfLine); } using SourceManagerRef = llvm::IntrusiveRefCntPtr<const clang::SourceManager>; auto iter = std::lower_bound(sourceManagersWithDiagnostics.begin(), sourceManagersWithDiagnostics.end(), &clangSrcMgr, [](const SourceManagerRef &inArray, const clang::SourceManager *toInsert) { return std::less<const clang::SourceManager *>()(inArray.get(), toInsert); }); if (iter->get() != &clangSrcMgr) sourceManagersWithDiagnostics.insert(iter, &clangSrcMgr); return loc; }
// Get the source range of the specified Stmt, ensuring that a semicolon is // included, if necessary - since the clang ranges do not guarantee this. SrcRange getStmtRangeWithSemicolon(const clang::Stmt *S, const clang::SourceManager& sm, const clang::LangOptions& options) { clang::SourceLocation SLoc = sm.getExpansionLoc(S->getLocStart()); clang::SourceLocation ELoc = sm.getExpansionLoc(S->getLocEnd()); unsigned start = sm.getFileOffset(SLoc); unsigned end = sm.getFileOffset(ELoc); // Below code copied from clang::Lexer::MeasureTokenLength(): clang::SourceLocation Loc = sm.getExpansionLoc(ELoc); std::pair<clang::FileID, unsigned> LocInfo = sm.getDecomposedLoc(Loc); llvm::StringRef Buffer = sm.getBufferData(LocInfo.first); const char *StrData = Buffer.data()+LocInfo.second; clang::Lexer TheLexer(Loc, options, Buffer.begin(), StrData, Buffer.end()); clang::Token TheTok; TheLexer.LexFromRawLexer(TheTok); // End copied code. end += TheTok.getLength(); // Check if we the source range did include the semicolon. if (TheTok.isNot(clang::tok::semi) && TheTok.isNot(clang::tok::r_brace)) { TheLexer.LexFromRawLexer(TheTok); if (TheTok.is(clang::tok::semi)) { end += TheTok.getLength(); } } return SrcRange(start, end); }
SourceLocation Utils::locForNextToken(SourceLocation loc, const clang::SourceManager &sm, const clang::LangOptions &lo) { std::pair<FileID, unsigned> locInfo = sm.getDecomposedLoc(loc); bool InvalidTemp = false; StringRef File = sm.getBufferData(locInfo.first, &InvalidTemp); if (InvalidTemp) { llvm::errs() << "Failed to get buffer data\n"; return {}; } const char *TokenBegin = File.data() + locInfo.second; Lexer lexer(sm.getLocForStartOfFile(locInfo.first), lo, File.begin(), TokenBegin, File.end()); Token Tok; lexer.LexFromRawLexer(Tok); SourceLocation TokenLoc = Tok.getLocation(); // Calculate how much whitespace needs to be skipped if any. unsigned NumWhitespaceChars = 0; const char *TokenEnd = sm.getCharacterData(TokenLoc) + Tok.getLength(); unsigned char C = *TokenEnd; while (isHorizontalWhitespace(C)) { C = *(++TokenEnd); NumWhitespaceChars++; } // Skip \r, \n, \r\n, or \n\r if (C == '\n' || C == '\r') { char PrevC = C; C = *(++TokenEnd); NumWhitespaceChars++; if ((C == '\n' || C == '\r') && C != PrevC) NumWhitespaceChars++; } return loc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars); }