cpp11-migrate: Add a class to support include directives modifications
The IncludeDirectives class helps with detecting and modifying #include
directives. For now it allows the users to add angled-includes in a source file.
This is a start for this class that will evolve in the future to add more
functionality.
This should fix the reverted commit r189037 (buildbot failures on Windows).
llvm-svn: 189354
diff --git a/clang-tools-extra/cpp11-migrate/Core/IncludeDirectives.h b/clang-tools-extra/cpp11-migrate/Core/IncludeDirectives.h
new file mode 100644
index 0000000..c1c5a7a
--- /dev/null
+++ b/clang-tools-extra/cpp11-migrate/Core/IncludeDirectives.h
@@ -0,0 +1,141 @@
+//===-- 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 CPP11_MIGRATE_INCLUDE_DIRECTIVES_H
+#define CPP11_MIGRATE_INCLUDE_DIRECTIVES_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Refactoring.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallPtrSet.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
+ /// \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 preferrably 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 // CPP11_MIGRATE_INCLUDE_DIRECTIVES_H