2121#include " llvm/Support/MemoryBuffer.h"
2222#include " llvm/Support/raw_ostream.h"
2323#include < memory>
24- using namespace clang ;
2524
25+ using namespace clang ;
26+ using namespace llvm ;
27+ using namespace html ;
2628
2729// / HighlightRange - Highlight a range in the source code with the specified
2830// / start/end tags. B/E must be in the same file. This ensures that
@@ -104,6 +106,32 @@ void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E,
104106 }
105107}
106108
109+ namespace clang ::html {
110+ struct RelexRewriteCache {
111+ // These structs mimic input arguments of HighlightRange().
112+ struct Highlight {
113+ SourceLocation B, E;
114+ std::string StartTag, EndTag;
115+ bool IsTokenRange;
116+ };
117+ struct RawHighlight {
118+ unsigned B, E;
119+ std::string StartTag, EndTag;
120+ };
121+
122+ // SmallVector isn't appropriate because these vectors are almost never small.
123+ using HighlightList = std::vector<Highlight>;
124+ using RawHighlightList = std::vector<RawHighlight>;
125+
126+ DenseMap<FileID, RawHighlightList> SyntaxHighlights;
127+ DenseMap<FileID, HighlightList> MacroHighlights;
128+ };
129+ } // namespace clang::html
130+
131+ html::RelexRewriteCacheRef html::instantiateRelexRewriteCache () {
132+ return std::make_shared<RelexRewriteCache>();
133+ }
134+
107135void html::EscapeText (Rewriter &R, FileID FID,
108136 bool EscapeSpaces, bool ReplaceTabs) {
109137
@@ -442,13 +470,18 @@ input.spoilerhider:checked + label + .spoiler{
442470// / information about keywords, macro expansions etc. This uses the macro
443471// / table state from the end of the file, so it won't be perfectly perfect,
444472// / but it will be reasonably close.
445- void html::SyntaxHighlight (Rewriter &R, FileID FID, const Preprocessor &PP) {
446- RewriteBuffer &RB = R.getEditBuffer (FID);
473+ static void SyntaxHighlightImpl (
474+ Rewriter &R, FileID FID, const Preprocessor &PP,
475+ llvm::function_ref<void (RewriteBuffer &, unsigned , unsigned , const char *,
476+ const char *, const char *)>
477+ HighlightRangeCallback) {
447478
479+ RewriteBuffer &RB = R.getEditBuffer (FID);
448480 const SourceManager &SM = PP.getSourceManager ();
449481 llvm::MemoryBufferRef FromFile = SM.getBufferOrFake (FID);
482+ const char *BufferStart = FromFile.getBuffer ().data ();
483+
450484 Lexer L (FID, FromFile, SM, PP.getLangOpts ());
451- const char *BufferStart = L.getBuffer ().data ();
452485
453486 // Inform the preprocessor that we want to retain comments as tokens, so we
454487 // can highlight them.
@@ -475,13 +508,13 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
475508
476509 // If this is a pp-identifier, for a keyword, highlight it as such.
477510 if (Tok.isNot (tok::identifier))
478- HighlightRange (RB, TokOffs, TokOffs+ TokLen, BufferStart,
479- " <span class='keyword'>" , " </span>" );
511+ HighlightRangeCallback (RB, TokOffs, TokOffs + TokLen, BufferStart,
512+ " <span class='keyword'>" , " </span>" );
480513 break ;
481514 }
482515 case tok::comment:
483- HighlightRange (RB, TokOffs, TokOffs+ TokLen, BufferStart,
484- " <span class='comment'>" , " </span>" );
516+ HighlightRangeCallback (RB, TokOffs, TokOffs + TokLen, BufferStart,
517+ " <span class='comment'>" , " </span>" );
485518 break ;
486519 case tok::utf8_string_literal:
487520 // Chop off the u part of u8 prefix
@@ -498,8 +531,8 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
498531 [[fallthrough]];
499532 case tok::string_literal:
500533 // FIXME: Exclude the optional ud-suffix from the highlighted range.
501- HighlightRange (RB, TokOffs, TokOffs+ TokLen, BufferStart,
502- " <span class='string_literal'>" , " </span>" );
534+ HighlightRangeCallback (RB, TokOffs, TokOffs + TokLen, BufferStart,
535+ " <span class='string_literal'>" , " </span>" );
503536 break ;
504537 case tok::hash: {
505538 // If this is a preprocessor directive, all tokens to end of line are too.
@@ -516,8 +549,8 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
516549 }
517550
518551 // Find end of line. This is a hack.
519- HighlightRange (RB, TokOffs, TokEnd, BufferStart,
520- " <span class='directive'>" , " </span>" );
552+ HighlightRangeCallback (RB, TokOffs, TokEnd, BufferStart,
553+ " <span class='directive'>" , " </span>" );
521554
522555 // Don't skip the next token.
523556 continue ;
@@ -527,12 +560,43 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
527560 L.LexFromRawLexer (Tok);
528561 }
529562}
563+ void html::SyntaxHighlight (Rewriter &R, FileID FID, const Preprocessor &PP,
564+ RelexRewriteCacheRef Cache) {
565+ RewriteBuffer &RB = R.getEditBuffer (FID);
566+ const SourceManager &SM = PP.getSourceManager ();
567+ llvm::MemoryBufferRef FromFile = SM.getBufferOrFake (FID);
568+ const char *BufferStart = FromFile.getBuffer ().data ();
569+
570+ if (Cache) {
571+ auto CacheIt = Cache->SyntaxHighlights .find (FID);
572+ if (CacheIt != Cache->SyntaxHighlights .end ()) {
573+ for (const RelexRewriteCache::RawHighlight &H : CacheIt->second ) {
574+ HighlightRange (RB, H.B , H.E , BufferStart, H.StartTag .data (),
575+ H.EndTag .data ());
576+ }
577+ return ;
578+ }
579+ }
580+
581+ // "Every time you would call HighlightRange, cache the inputs as well."
582+ auto HighlightRangeCallback = [&](RewriteBuffer &RB, unsigned B, unsigned E,
583+ const char *BufferStart,
584+ const char *StartTag, const char *EndTag) {
585+ HighlightRange (RB, B, E, BufferStart, StartTag, EndTag);
586+
587+ if (Cache)
588+ Cache->SyntaxHighlights [FID].push_back ({B, E, StartTag, EndTag});
589+ };
590+
591+ SyntaxHighlightImpl (R, FID, PP, HighlightRangeCallback);
592+ }
593+
594+ static void HighlightMacrosImpl (
595+ Rewriter &R, FileID FID, const Preprocessor &PP,
596+ llvm::function_ref<void (Rewriter &, SourceLocation, SourceLocation,
597+ const char *, const char *, bool )>
598+ HighlightRangeCallback) {
530599
531- // / HighlightMacros - This uses the macro table state from the end of the
532- // / file, to re-expand macros and insert (into the HTML) information about the
533- // / macro expansions. This won't be perfectly perfect, but it will be
534- // / reasonably close.
535- void html::HighlightMacros (Rewriter &R, FileID FID, const Preprocessor& PP) {
536600 // Re-lex the raw token stream into a token buffer.
537601 const SourceManager &SM = PP.getSourceManager ();
538602 std::vector<Token> TokenStream;
@@ -659,11 +723,44 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
659723 // get highlighted.
660724 Expansion = " <span class='macro_popup'>" + Expansion + " </span></span>" ;
661725
662- HighlightRange (R, LLoc.getBegin (), LLoc.getEnd (), " <span class='macro'>" ,
663- Expansion.c_str (), LLoc.isTokenRange ());
726+ HighlightRangeCallback (R, LLoc.getBegin (), LLoc.getEnd (),
727+ " <span class='macro'>" , Expansion.c_str (),
728+ LLoc.isTokenRange ());
664729 }
665730
666731 // Restore the preprocessor's old state.
667732 TmpPP.setDiagnostics (*OldDiags);
668733 TmpPP.setPragmasEnabled (PragmasPreviouslyEnabled);
669734}
735+
736+ // / HighlightMacros - This uses the macro table state from the end of the
737+ // / file, to re-expand macros and insert (into the HTML) information about the
738+ // / macro expansions. This won't be perfectly perfect, but it will be
739+ // / reasonably close.
740+ void html::HighlightMacros (Rewriter &R, FileID FID, const Preprocessor &PP,
741+ RelexRewriteCacheRef Cache) {
742+ if (Cache) {
743+ auto CacheIt = Cache->MacroHighlights .find (FID);
744+ if (CacheIt != Cache->MacroHighlights .end ()) {
745+ for (const RelexRewriteCache::Highlight &H : CacheIt->second ) {
746+ HighlightRange (R, H.B , H.E , H.StartTag .data (), H.EndTag .data (),
747+ H.IsTokenRange );
748+ }
749+ return ;
750+ }
751+ }
752+
753+ // "Every time you would call HighlightRange, cache the inputs as well."
754+ auto HighlightRangeCallback = [&](Rewriter &R, SourceLocation B,
755+ SourceLocation E, const char *StartTag,
756+ const char *EndTag, bool isTokenRange) {
757+ HighlightRange (R, B, E, StartTag, EndTag, isTokenRange);
758+
759+ if (Cache) {
760+ Cache->MacroHighlights [FID].push_back (
761+ {B, E, StartTag, EndTag, isTokenRange});
762+ }
763+ };
764+
765+ HighlightMacrosImpl (R, FID, PP, HighlightRangeCallback);
766+ }
0 commit comments