//===-- 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 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 /// \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 EntryVec; // A list of source locations. typedef std::vector LocationVec; // Associates files to their includes. typedef llvm::DenseMap FileToEntriesMap; // Associates headers to their include guards if any. The location is the // location of the hash from the #define. typedef llvm::DenseMap HeaderToGuardMap; /// \brief Type used by \c lookForInclude() to keep track of the files that /// have already been processed. typedef llvm::SmallPtrSet 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 findFileHeaderEndOffset(clang::FileID FID) const; /// \brief Finds the offset where an angled include should be added and /// returns a pair (FileOffset, NewLineFlags). std::pair 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 IncludeAsWrittenToLocationsMap; HeaderToGuardMap HeaderToGuard; }; #endif // CLANG_MODERNIZE_INCLUDE_DIRECTIVES_H