llvm-project/clang-tools-extra/cpp11-migrate/Core/FileOverrides.h

236 lines
7.8 KiB
C++

//===-- Core/FileOverrides.h ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file provides types and functionality for dealing with source
/// and header file content overrides.
///
//===----------------------------------------------------------------------===//
#ifndef CPP11_MIGRATE_FILE_OVERRIDES_H
#define CPP11_MIGRATE_FILE_OVERRIDES_H
#include "Core/ReplacementsYaml.h"
#include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/StringMap.h"
// Forward Declarations
namespace llvm {
template <typename T>
class SmallVectorImpl;
} // namespace llvm
namespace clang {
class SourceManager;
class Rewriter;
} // namespace clang
/// \brief Class encapsulating a list of \c tooling::Range with some
/// convenience methods.
///
/// The ranges stored are used to keep track of the overriden parts of a file.
class ChangedRanges {
typedef std::vector<clang::tooling::Range> RangeVec;
public:
typedef RangeVec::const_iterator const_iterator;
/// \brief Create new ranges from the replacements and adjust existing one
/// to remove replaced parts.
///
/// Note that all replacements should come from the same file.
void adjustChangedRanges(const clang::tooling::Replacements &Replaces);
/// \brief Iterators.
/// @{
const_iterator begin() const { return Ranges.begin(); }
const_iterator end() const { return Ranges.end(); }
/// @}
private:
void coalesceRanges();
RangeVec Ranges;
};
/// \brief Container for storing override information for a single headers.
class HeaderOverride {
public:
/// \brief Constructors.
/// @{
HeaderOverride() {}
HeaderOverride(llvm::StringRef TargetFile,
llvm::StringRef MainSourceFile) {
MigratorDoc.TargetFile = TargetFile;
MigratorDoc.MainSourceFile= MainSourceFile;
}
/// @}
/// \brief Getter for FileName.
llvm::StringRef getFileName() const {
return MigratorDoc.TargetFile;
}
/// \brief Accessor for ContentOverride.
/// @{
llvm::StringRef getContentOverride() const { return ContentOverride; }
void setContentOverride(const llvm::StringRef S) { ContentOverride = S; }
/// @}
/// \brief Getter for Changes.
const ChangedRanges &getChanges() const { return Changes; }
/// \brief Swaps the content of ContentOverride with \p S.
void swapContentOverride(std::string &S) { ContentOverride.swap(S); }
/// \brief Getter for MigratorDoc.
const MigratorDocument &getMigratorDoc() const {
return MigratorDoc;
}
/// \brief Stores the replacements made by a transform to the header this
/// object represents.
void recordReplacements(const clang::tooling::Replacements &Replaces);
/// \brief Helper function to adjust the changed ranges.
void adjustChangedRanges(const clang::tooling::Replacements &Replaces) {
Changes.adjustChangedRanges(Replaces);
}
private:
std::string ContentOverride;
ChangedRanges Changes;
MigratorDocument MigratorDoc;
};
/// \brief Container mapping header file names to override information.
typedef llvm::StringMap<HeaderOverride> HeaderOverrides;
/// \brief Container storing the file content overrides for a source file and
/// any headers included by the source file either directly or indirectly to
/// which changes have been made.
class SourceOverrides {
public:
SourceOverrides(llvm::StringRef MainFileName, bool TrackChanges);
/// \brief Accessors.
/// @{
llvm::StringRef getMainFileName() const { return MainFileName; }
llvm::StringRef getMainFileContent() const { return MainFileOverride; }
const ChangedRanges &getChangedRanges() const { return MainFileChanges; }
/// \brief Is file change tracking enabled?
///
/// Tracking file changes can be useful to reformat the code for example.
bool isTrackingFileChanges() const { return TrackChanges; }
/// @}
/// \brief Indicates if the source file has been overridden.
///
/// It's possible for a source to remain unchanged while only headers are
/// changed.
bool isSourceOverriden() const { return !MainFileOverride.empty(); }
/// \brief Override the file contents by applying all the replacements.
///
/// \param Replaces The replacements to apply.
/// \param SM A user provided SourceManager to be used when applying rewrites.
void applyReplacements(clang::tooling::Replacements &Replaces,
clang::SourceManager &SM);
void applyReplacements(clang::tooling::Replacements &Replaces);
/// \brief Convenience function for applying this source's overrides to
/// the given SourceManager.
void applyOverrides(clang::SourceManager &SM) const;
/// \brief Iterators.
/// @{
HeaderOverrides::iterator headers_begin() { return Headers.begin(); }
HeaderOverrides::iterator headers_end() { return Headers.end(); }
HeaderOverrides::const_iterator headers_begin() const {
return Headers.begin();
}
HeaderOverrides::const_iterator headers_end() const { return Headers.end(); }
/// @}
private:
typedef llvm::StringMap<clang::tooling::Replacements> ReplacementsMap;
/// \brief Flatten the Rewriter buffers of \p Rewrite and store results as
/// file content overrides.
void applyRewrites(clang::Rewriter &Rewrite);
/// \brief Adjust the changed ranges to reflect the parts of the files that
/// have been replaced.
void adjustChangedRanges(const clang::tooling::Replacements &Replaces,
const ReplacementsMap &HeadersReplaces);
const std::string MainFileName;
std::string MainFileOverride;
const bool TrackChanges;
ChangedRanges MainFileChanges;
HeaderOverrides Headers;
};
/// \brief Maps source file names to content override information.
class FileOverrides {
public:
typedef llvm::StringMap<SourceOverrides *> SourceOverridesMap;
typedef SourceOverridesMap::const_iterator const_iterator;
/// \brief Construct the SourceOverrides manager.
///
/// \param TrackChanges Wether or not the \c SourceOverrides should keep track
/// of changes. See \c SourceOverrides::isTrackingFileChanges().
FileOverrides(bool TrackChanges) : TrackChanges(TrackChanges) {}
~FileOverrides();
const_iterator find(llvm::StringRef Filename) const {
return Overrides.find(Filename);
}
/// \brief Get the \c SourceOverrides for \p Filename, creating it if
/// necessary.
SourceOverrides &getOrCreate(llvm::StringRef Filename);
/// \brief Iterators.
/// @{
const_iterator begin() const { return Overrides.begin(); }
const_iterator end() const { return Overrides.end(); }
/// @}
private:
FileOverrides(const FileOverrides &) LLVM_DELETED_FUNCTION;
FileOverrides &operator=(const FileOverrides &) LLVM_DELETED_FUNCTION;
SourceOverridesMap Overrides;
const bool TrackChanges;
};
/// \brief Generate a unique filename to store the replacements.
///
/// Generates a unique filename in the same directory as the header file. The
/// filename is based on the following model:
///
/// source.cpp_header.h_%%_%%_%%_%%_%%_%%.yaml
///
/// where all '%' will be replaced by a randomly chosen hex number.
///
/// @param SourceFile Full path to the source file.
/// @param HeaderFile Full path to the header file.
/// @param Result The resulting unique filename in the same directory as the
/// header file.
/// @param Error Description of the error if there is any.
/// @returns true if succeeded, false otherwise.
bool generateReplacementsFileName(llvm::StringRef SourceFile,
llvm::StringRef HeaderFile,
llvm::SmallVectorImpl<char> &Result,
llvm::SmallVectorImpl<char> &Error);
#endif // CPP11_MIGRATE_FILE_OVERRIDES_H