1 //===-- ApplyReplacements.h - Deduplicate and apply replacements -- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file provides the interface for deduplicating, detecting
11 /// conflicts in, and applying collections of Replacements.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_APPLYREPLACEMENTS_H
16 #define LLVM_CLANG_APPLYREPLACEMENTS_H
17 
18 #include "clang/Tooling/Core/Diagnostic.h"
19 #include "clang/Tooling/Refactoring.h"
20 #include "clang/Tooling/Refactoring/AtomicChange.h"
21 #include "llvm/ADT/StringMap.h"
22 #include "llvm/ADT/StringRef.h"
23 #include <string>
24 #include <system_error>
25 #include <vector>
26 
27 namespace clang {
28 
29 class DiagnosticsEngine;
30 
31 namespace replace {
32 
33 /// Collection of TranslationUnitReplacements.
34 typedef std::vector<clang::tooling::TranslationUnitReplacements> TUReplacements;
35 
36 /// Collection of TranslationUnitReplacement files.
37 typedef std::vector<std::string> TUReplacementFiles;
38 
39 /// Collection of TranslationUniDiagnostics.
40 typedef std::vector<clang::tooling::TranslationUnitDiagnostics> TUDiagnostics;
41 
42 /// Map mapping file name to a set of AtomicChange targeting that file.
43 using FileToChangesMap =
44     llvm::DenseMap<clang::FileEntryRef, std::vector<tooling::AtomicChange>>;
45 
46 /// Recursively descends through a directory structure rooted at \p
47 /// Directory and attempts to deserialize *.yaml files as
48 /// TranslationUnitReplacements. All docs that successfully deserialize are
49 /// added to \p TUs.
50 ///
51 /// Directories starting with '.' are ignored during traversal.
52 ///
53 /// \param[in] Directory Directory to begin search for serialized
54 /// TranslationUnitReplacements or TranslationUnitDiagnostics.
55 /// \param[out] TUs Collection of all found and deserialized
56 /// TranslationUnitReplacements or TranslationUnitDiagnostics.
57 /// \param[out] TUFiles Collection of all TranslationUnitReplacement or
58 /// TranslationUnitDiagnostics files found in \c Directory.
59 /// \param[in] Diagnostics DiagnosticsEngine used for error output.
60 ///
61 /// \returns An error_code indicating success or failure in navigating the
62 /// directory structure.
63 template <typename TranslationUnits>
64 std::error_code collectReplacementsFromDirectory(
65     const llvm::StringRef Directory, TranslationUnits &TUs,
66     TUReplacementFiles &TUFiles,
67     clang::DiagnosticsEngine &Diagnostics) = delete;
68 
69 template <>
70 std::error_code collectReplacementsFromDirectory(
71     const llvm::StringRef Directory, TUReplacements &TUs,
72     TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics);
73 
74 template <>
75 std::error_code collectReplacementsFromDirectory(
76     const llvm::StringRef Directory, TUDiagnostics &TUs,
77     TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics);
78 
79 /// Deduplicate, check for conflicts, and extract all Replacements stored
80 /// in \c TUs. Conflicting replacements are skipped.
81 ///
82 /// \post For all (key,value) in FileChanges, value[i].getOffset() <=
83 /// value[i+1].getOffset().
84 ///
85 /// \param[in] TUs Collection of TranslationUnitReplacements or
86 /// TranslationUnitDiagnostics to merge, deduplicate, and test for conflicts.
87 /// \param[out] FileChanges Container grouping all changes by the
88 /// file they target. Only non conflicting replacements are kept into
89 /// FileChanges.
90 /// \param[in] SM SourceManager required for conflict reporting.
91 ///
92 /// \returns \parblock
93 ///          \li true If all changes were converted successfully.
94 ///          \li false If there were conflicts.
95 bool mergeAndDeduplicate(const TUReplacements &TUs, const TUDiagnostics &TUDs,
96                          FileToChangesMap &FileChanges,
97                          clang::SourceManager &SM,
98                          bool IgnoreInsertConflict = false);
99 
100 /// Apply \c AtomicChange on File and rewrite it.
101 ///
102 /// \param[in] File Path of the file where to apply AtomicChange.
103 /// \param[in] Changes to apply.
104 /// \param[in] Spec For code cleanup and formatting.
105 /// \param[in] Diagnostics DiagnosticsEngine used for error output.
106 ///
107 /// \returns The changed code if all changes are applied successfully;
108 /// otherwise, an llvm::Error carrying llvm::StringError or an error_code.
109 llvm::Expected<std::string>
110 applyChanges(StringRef File, const std::vector<tooling::AtomicChange> &Changes,
111              const tooling::ApplyChangesSpec &Spec,
112              DiagnosticsEngine &Diagnostics);
113 
114 /// Delete the replacement files.
115 ///
116 /// \param[in] Files Replacement files to delete.
117 /// \param[in] Diagnostics DiagnosticsEngine used for error output.
118 ///
119 /// \returns \parblock
120 ///          \li true If all files have been deleted successfully.
121 ///          \li false If at least one or more failures occur when deleting
122 /// files.
123 bool deleteReplacementFiles(const TUReplacementFiles &Files,
124                             clang::DiagnosticsEngine &Diagnostics);
125 
126 } // end namespace replace
127 } // end namespace clang
128 
129 #endif // LLVM_CLANG_APPLYREPLACEMENTS_H
130