1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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
|