llvm-project/clang-tools-extra/clang-modernize/Core/IncludeDirectives.h

142 lines
5.3 KiB
C++

//===-- Core/IncludeDirectives.h - Include directives handling --*- 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 declares the IncludeDirectives class that helps with
/// detecting and modifying \#include directives.
///
//===----------------------------------------------------------------------===//
#ifndef CLANG_MODERNIZE_INCLUDE_DIRECTIVES_H
#define CLANG_MODERNIZE_INCLUDE_DIRECTIVES_H
#include "clang/Basic/SourceLocation.h"
#include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringRef.h"
#include <vector>
namespace clang {
class Preprocessor;
} // namespace clang
/// \brief Support for include directives handling.
///
/// This class should be created with a \c clang::CompilerInstance before the
/// file is preprocessed in order to collect the inclusion information. It can
/// be queried as long as the compiler instance is valid.
class IncludeDirectives {
public:
IncludeDirectives(clang::CompilerInstance &CI);
/// \brief Add an angled include to a the given file.
///
/// \param File A file accessible by a SourceManager
/// \param Include The include file as it should be written in the code.
///
/// \returns \parblock
/// \li A null Replacement (check using \c Replacement::isApplicable()), if
/// the \c Include is already visible from \c File.
/// \li Otherwise, a non-null Replacement that, when applied, inserts an
/// \c \#include into \c File.
clang::tooling::Replacement addAngledInclude(llvm::StringRef File,
llvm::StringRef Include);
clang::tooling::Replacement addAngledInclude(const clang::FileEntry *File,
llvm::StringRef Include);
/// \brief Check if \p Include is included by \p File or any of the files
/// \p File includes.
bool hasInclude(const clang::FileEntry *File, llvm::StringRef Include) const;
private:
friend class IncludeDirectivesPPCallback;
/// \brief Contains information about an inclusion.
class Entry {
public:
Entry(clang::SourceLocation HashLoc, const clang::FileEntry *IncludedFile,
bool Angled)
: HashLoc(HashLoc), IncludedFile(IncludedFile), Angled(Angled) {}
/// \brief The location of the '#'.
clang::SourceLocation getHashLocation() const { return HashLoc; }
/// \brief The file included by this include directive.
const clang::FileEntry *getIncludedFile() const { return IncludedFile; }
/// \brief \c true if the include use angle brackets, \c false otherwise
/// when using of quotes.
bool isAngled() const { return Angled; }
private:
clang::SourceLocation HashLoc;
const clang::FileEntry *IncludedFile;
bool Angled;
};
// A list of entries.
typedef std::vector<Entry> EntryVec;
// A list of source locations.
typedef std::vector<clang::SourceLocation> LocationVec;
// Associates files to their includes.
typedef llvm::DenseMap<const clang::FileEntry *, EntryVec> FileToEntriesMap;
// Associates headers to their include guards if any. The location is the
// location of the hash from the #define.
typedef llvm::DenseMap<const clang::FileEntry *, clang::SourceLocation>
HeaderToGuardMap;
/// \brief Type used by \c lookForInclude() to keep track of the files that
/// have already been processed.
typedef llvm::SmallPtrSet<const clang::FileEntry *, 32> SeenFilesSet;
/// \brief Recursively look if an include is included by \p File or any of the
/// headers \p File includes.
///
/// \param File The file where to start the search.
/// \param IncludeLocs These are the hash locations of the \#include
/// directives we are looking for.
/// \param Seen Used to avoid visiting a same file more than once during the
/// recursion.
bool lookForInclude(const clang::FileEntry *File,
const LocationVec &IncludeLocs, SeenFilesSet &Seen) const;
/// \brief Find the end of a file header and returns a pair (FileOffset,
/// NewLineFlags).
///
/// Source files often contain a file header (copyright, license, explanation
/// of the file content). An \#include should preferably be put after this.
std::pair<unsigned, unsigned>
findFileHeaderEndOffset(clang::FileID FID) const;
/// \brief Finds the offset where an angled include should be added and
/// returns a pair (FileOffset, NewLineFlags).
std::pair<unsigned, unsigned>
angledIncludeInsertionOffset(clang::FileID FID) const;
/// \brief Find the location of an include directive that can be used to
/// insert an inclusion after.
///
/// If no such include exists returns a null SourceLocation.
clang::SourceLocation angledIncludeHintLoc(clang::FileID FID) const;
clang::CompilerInstance &CI;
clang::SourceManager &Sources;
FileToEntriesMap FileToEntries;
// maps include filename as written in the source code to the source locations
// where it appears
llvm::StringMap<LocationVec> IncludeAsWrittenToLocationsMap;
HeaderToGuardMap HeaderToGuard;
};
#endif // CLANG_MODERNIZE_INCLUDE_DIRECTIVES_H