File: OutputHelper.h

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (112 lines) | stat: -rw-r--r-- 4,964 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TOOLS_CLANG_AST_REWRITER_OUTPUTHELPER_H_
#define TOOLS_CLANG_AST_REWRITER_OUTPUTHELPER_H_

#include <string>

#include "clang/Tooling/Core/Replacement.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/StringSet.h"

// This is a general helper class for emitting the substitution directives
// consumed by apply_edits.py.
// See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/clang_tool_refactoring.md
// for general documentation on the format.
//
// From a consumer's perspective, the most important functions are `Delete`,
// `Replace`, and `Wrap`, which each emit a substitution directive to stdout.
// The class also maintains a list of headers to be added to every file where a
// replacement occurred; the directives are emitted at the end of the file.
//
// For the most part, you should be able to re-use this class without any
// changes. It's possible certain use cases may require more complex logic, if
// e.g. you're doing multiple kinds of replacement at once, and different ones
// need to add different sets of headers.
//
// The substitution directives all take a CharSourceRange as their primary
// argument. Despite the name, these represent a range of _either_ characters or
// tokens, as reported by their isTokenRange() method. Both versions store a
// start and an end SourceLocation; in the 'char' case, these point to the first
// and last character of the range, respectively. In the 'token' case, they
// point to the first character in the first/last token of the range. This means
// that typically they will point _before_ the last character of the range, e.g.
// in the code "Foo + Bar", the end of a character range will point at 'r',
// while the end of a token range will point at 'B'. In both cases, the start
// of the range will be 'F'.
//
// From a usage perspective, the primary difference is which construction
// function you should call. If you have character-granular information, then
// call CharSourceRange::getCharRange; if you have token-level information, then
// call CharSourceRange::getTokenRange.
class OutputHelper : public clang::tooling::SourceFileCallbacks {
 public:
  OutputHelper() = default;
  ~OutputHelper() = default;

  OutputHelper(const OutputHelper&) = delete;
  OutputHelper& operator=(const OutputHelper&) = delete;

  OutputHelper(llvm::StringSet<> headers_to_add)
      : headers_to_add_(std::move(headers_to_add)) {};

  // Replaces `replacement_range` with `replacement_text`.
  void Replace(const clang::CharSourceRange& replacement_range,
               std::string replacement_text,
               const clang::SourceManager& source_manager,
               const clang::LangOptions& lang_opts);

  // Deletes `replacement_range`.
  void Delete(const clang::CharSourceRange& replacement_range,
              const clang::SourceManager& source_manager,
              const clang::LangOptions& lang_opts);

  // Inserts `lhs` and `rhs` to the left and right of `replacement_range`.
  void Wrap(const clang::CharSourceRange& replacement_range,
            std::string_view lhs,
            std::string_view rhs,
            const clang::SourceManager& source_manager,
            const clang::LangOptions& lang_opts);

 private:
  // By inheriting from clang::tooling::SourceFileCallbacks, OutputHelper
  // automatically executes setup and teardown code at the beginning/end of each
  // file.

  // This is run automatically when the tool is first invoked.
  bool handleBeginSource(clang::CompilerInstance& compiler) override;

  // This is run automatically at the end of the file.
  void handleEndSource() override;

  // Called by PrintReplacement to determine if we should actually replace in
  // this file.
  bool ShouldOutput() { return current_language_ == clang::Language::CXX; }

  // Emit the requested replacement in the proper format.
  void PrintReplacement(llvm::StringRef file_path,
                        unsigned offset,
                        unsigned length,
                        std::string_view replacement_text) {
    if (ShouldOutput()) {
      files_replaced_in_.insert(file_path);
      std::string final_text = std::string(replacement_text);
      // The rewriting format expects newlines to be replaced with \0
      std::replace(final_text.begin(), final_text.end(), '\n', '\0');
      llvm::outs() << "r:::" << file_path << ":::" << offset << ":::" << length
                   << ":::" << final_text << "\n";
    }
  }

  // The language of the file we're currently looking at.
  clang::Language current_language_ = clang::Language::Unknown;
  // At the end, we'll add additional headers to each file we emitted a
  // replacement directive for.
  llvm::StringSet<> files_replaced_in_;
  llvm::StringSet<> headers_to_add_;
};

#endif  // TOOLS_CLANG_AST_REWRITER_OUTPUTHELPER_H_