|
| 1 | +#include "swift/AST/DiagnosticConsumer.h" |
| 2 | +#include "swift/AST/DiagnosticEngine.h" |
1 | 3 | #include "swift/Basic/LangOptions.h"
|
2 | 4 | #include "swift/Basic/SourceManager.h"
|
3 | 5 | #include "swift/Parse/Lexer.h"
|
@@ -703,3 +705,78 @@ TEST_F(LexerTest, NestedPlaceholder) {
|
703 | 705 | std::vector<Token> Toks = checkLex(Source, ExpectedTokens);
|
704 | 706 | EXPECT_EQ("<#aa#>", Toks[2].getText());
|
705 | 707 | }
|
| 708 | + |
| 709 | +class StringCaptureDiagnosticConsumer : public DiagnosticConsumer { |
| 710 | +public: |
| 711 | + virtual void handleDiagnostic(SourceManager &SM, SourceLoc Loc, |
| 712 | + DiagnosticKind Kind, StringRef FormatString, |
| 713 | + ArrayRef<DiagnosticArgument> FormatArgs, |
| 714 | + const swift::DiagnosticInfo &Info) override { |
| 715 | + std::string DiagMsg; |
| 716 | + llvm::raw_string_ostream DiagOS(DiagMsg); |
| 717 | + DiagnosticEngine::formatDiagnosticText(DiagOS, FormatString, FormatArgs); |
| 718 | + auto LC = SM.getLineAndColumn(Loc); |
| 719 | + std::ostringstream StrOS; |
| 720 | + StrOS << LC.first << ", " << LC.second << ": " << DiagOS.str(); |
| 721 | + messages.push_back(StrOS.str()); |
| 722 | + } |
| 723 | + |
| 724 | + std::vector<std::string> messages; |
| 725 | +}; |
| 726 | + |
| 727 | +bool containsPrefix(const std::vector<std::string> &strs, |
| 728 | + const std::string &prefix) { |
| 729 | + for (auto &str : strs) { |
| 730 | + if (StringRef(str).startswith(StringRef(prefix))) { |
| 731 | + return true; |
| 732 | + } |
| 733 | + } |
| 734 | + return false; |
| 735 | +} |
| 736 | + |
| 737 | +TEST_F(LexerTest, DiagnoseEmbeddedNul) { |
| 738 | + const char Source[] = " \0 \0 aaa \0 \0 bbb"; |
| 739 | + size_t SourceLen = sizeof(Source) - 1; |
| 740 | + |
| 741 | + LangOptions LangOpts; |
| 742 | + SourceManager SourceMgr; |
| 743 | + unsigned BufferID = SourceMgr.addMemBufferCopy(StringRef(Source, SourceLen)); |
| 744 | + |
| 745 | + StringCaptureDiagnosticConsumer DiagConsumer; |
| 746 | + DiagnosticEngine Diags(SourceMgr); |
| 747 | + Diags.addConsumer(DiagConsumer); |
| 748 | + |
| 749 | + Lexer L(LangOpts, SourceMgr, BufferID, &Diags, |
| 750 | + /*InSILMode=*/false, CommentRetentionMode::None, |
| 751 | + TriviaRetentionMode::WithTrivia); |
| 752 | + |
| 753 | + ASSERT_TRUE(containsPrefix(DiagConsumer.messages, |
| 754 | + "1, 2: nul character embedded in middle of file")); |
| 755 | + ASSERT_TRUE(containsPrefix(DiagConsumer.messages, |
| 756 | + "1, 4: nul character embedded in middle of file")); |
| 757 | +} |
| 758 | + |
| 759 | +TEST_F(LexerTest, DiagnoseEmbeddedNulOffset) { |
| 760 | + const char Source[] = " \0 \0 aaa \0 \0 bbb"; |
| 761 | + size_t SourceLen = sizeof(Source) - 1; |
| 762 | + |
| 763 | + LangOptions LangOpts; |
| 764 | + SourceManager SourceMgr; |
| 765 | + unsigned BufferID = SourceMgr.addMemBufferCopy(StringRef(Source, SourceLen)); |
| 766 | + |
| 767 | + StringCaptureDiagnosticConsumer DiagConsumer; |
| 768 | + DiagnosticEngine Diags(SourceMgr); |
| 769 | + Diags.addConsumer(DiagConsumer); |
| 770 | + |
| 771 | + Lexer L(LangOpts, SourceMgr, BufferID, &Diags, |
| 772 | + /*InSILMode=*/false, CommentRetentionMode::None, |
| 773 | + TriviaRetentionMode::WithTrivia, |
| 774 | + /*Offset=*/5, /*EndOffset=*/SourceLen); |
| 775 | + |
| 776 | + // Current implementation has a bug. |
| 777 | + // It must be FALSE because Offset = 5. |
| 778 | + ASSERT_TRUE(containsPrefix(DiagConsumer.messages, |
| 779 | + "1, 2: nul character embedded in middle of file")); |
| 780 | + ASSERT_TRUE(containsPrefix(DiagConsumer.messages, |
| 781 | + "1, 4: nul character embedded in middle of file")); |
| 782 | +} |
0 commit comments