Enhanced search paths of mapping files. Patch by Kim Gräsman.

Search for mapping files:
- in the current working directory;
- in the directory where IWYU executable is located;
- in the directory where another discovered mapping file is located.
This commit is contained in:
Volodymyr Sapsai 2012-11-25 21:26:06 +00:00
parent 5e6ee85bf7
commit 40999861b2
7 changed files with 130 additions and 14 deletions

14
iwyu.cc
View File

@ -3644,12 +3644,19 @@ class IwyuAstConsumer
// We use an ASTFrontendAction to hook up IWYU with Clang.
class IwyuAction : public ASTFrontendAction {
public:
IwyuAction(const char* executable_path)
: executable_path_(executable_path)
{
}
protected:
virtual ASTConsumer* CreateASTConsumer(CompilerInstance& compiler, // NOLINT
llvm::StringRef /* dummy */) {
// Do this first thing after getting our hands on a CompilerInstance.
InitGlobals(&compiler.getSourceManager(),
&compiler.getPreprocessor().getHeaderSearchInfo());
&compiler.getPreprocessor().getHeaderSearchInfo(),
executable_path_);
IwyuPreprocessorInfo* const preprocessor_consumer
= new IwyuPreprocessorInfo();
@ -3662,6 +3669,9 @@ class IwyuAction : public ASTFrontendAction {
compiler.getPreprocessor().addCommentHandler(preprocessor_consumer);
return ast_consumer;
}
private:
std::string executable_path_;
};
@ -3704,7 +3714,7 @@ int main(int argc, char **argv) {
CHECK_(compiler && "Failed to process argv");
// Create and execute the frontend to generate an LLVM bitcode module.
llvm::OwningPtr<clang::ASTFrontendAction> action(new IwyuAction);
llvm::OwningPtr<clang::ASTFrontendAction> action(new IwyuAction(clang_argv[0]));
if (!compiler->ExecuteAction(*action))
return 1;

View File

@ -49,7 +49,6 @@ static SourceManagerCharacterDataGetter* data_getter = NULL;
static FullUseCache* function_calls_full_use_cache = NULL;
static FullUseCache* class_members_full_use_cache = NULL;
static void PrintHelp(const char* extra_msg) {
printf("USAGE: iwyu [-Xiwyu --iwyu_opt]... <clang opts> <source file>\n"
"Here are the <opts> you can specify:\n"
@ -182,7 +181,9 @@ static vector<HeaderSearchPath> ComputeHeaderSearchPaths(
return NormalizeHeaderSearchPaths(search_path_map);
}
void InitGlobals(clang::SourceManager* sm, clang::HeaderSearch* header_search) {
void InitGlobals(clang::SourceManager* sm,
clang::HeaderSearch* header_search,
const std::string& executable_path) {
CHECK_(sm && "InitGlobals() needs a non-NULL SourceManager");
source_manager = sm;
data_getter = new SourceManagerCharacterDataGetter(*source_manager);
@ -199,6 +200,11 @@ void InitGlobals(clang::SourceManager* sm, clang::HeaderSearch* header_search) {
VERRS(6) << "Search path: " << it->path << " (" << path_type_name << ")\n";
}
// Set up mapping file search paths.
include_picker->AddMappingFileSearchPath(".");
include_picker->AddMappingFileSearchPath(GetParentPath(executable_path));
// Add mappings.
for (Each<string> it(&GlobalFlags().mapping_files); !it.AtEnd(); ++it) {
include_picker->AddMappingsFromFile(*it);
}

View File

@ -42,7 +42,8 @@ class SourceManagerCharacterDataGetter;
int ParseIwyuCommandlineFlags(int argc, char** argv);
void InitGlobals(clang::SourceManager* source_manager,
clang::HeaderSearch* header_search);
clang::HeaderSearch* header_search,
const std::string& executable_path);
// Can be called by tests -- doesn't need a SourceManager or
// argc/argv. Note that GlobalSourceManager() and DefaultDataGetter()

View File

@ -26,10 +26,9 @@
#include "iwyu_verrs.h"
#include "port.h" // for CHECK_
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"
@ -279,6 +278,16 @@ void IncludePicker::AddDirectInclude(const string& includer_filepath,
}
}
void IncludePicker::AddMappingFileSearchPath(const string& path) {
string absolute_path = MakeAbsolutePath(path);
if (std::find(mapping_file_search_path_.begin(),
mapping_file_search_path_.end(),
absolute_path) == mapping_file_search_path_.end()) {
VERRS(6) << "Adding mapping file search path: " << absolute_path << "\n";
mapping_file_search_path_.push_back(absolute_path);
}
}
void IncludePicker::AddMapping(const string& map_from, const string& map_to) {
VERRS(4) << "Adding mapping from " << map_from << " to " << map_to << "\n";
CHECK_(!has_called_finalize_added_include_lines_ && "Can't mutate anymore");
@ -493,6 +502,33 @@ string IncludePicker::MaybeGetIncludeNameAsWritten(
return value ? *value : "";
}
error_code IncludePicker::TryReadMappingFile(
const string& filename,
OwningPtr<MemoryBuffer>& buffer) const {
string absolute_path;
if (IsAbsolutePath(filename)) {
VERRS(5) << "Absolute mapping filename: " << filename << ".\n";
absolute_path = filename;
} else {
VERRS(5) << "Relative mapping filename: " << filename << ". "
<< "Scanning search path.\n";
// Scan search path
for (Each<string> it(&mapping_file_search_path_); !it.AtEnd(); ++it) {
string candidate = MakeAbsolutePath(*it, filename);
if (llvm::sys::fs::exists(candidate)) {
absolute_path = candidate;
VERRS(5) << "Found mapping file: " << candidate << ".\n";
break;
}
}
}
error_code error = MemoryBuffer::getFile(absolute_path, buffer);
VERRS(5) << "Opened mapping file: " << filename << "? "
<< error.message() << "\n";
return error;
}
vector<string> IncludePicker::GetCandidateHeadersForSymbol(
const string& symbol) const {
CHECK_(has_called_finalize_added_include_lines_ && "Must finalize includes");
@ -579,13 +615,11 @@ bool IncludePicker::HasMapping(const string& map_from_filepath,
// We use this to maintain mappings externally, to make it easier
// to update/adjust to local circumstances.
void IncludePicker::AddMappingsFromFile(const string& filename) {
// TODO(kimgr): Resolve absolute mapping path along some search path
// e.g. look also next to IWYU binary.
OwningPtr<MemoryBuffer> buffer;
llvm::error_code result = MemoryBuffer::getFile(filename, buffer);
if (result != 0) {
error_code error = TryReadMappingFile(filename, buffer);
if (error) {
errs() << "Cannot open mapping file '" << filename << "': "
<< result.message() << ".\n";
<< error.message() << ".\n";
return;
}
@ -680,7 +714,7 @@ void IncludePicker::AddMappingsFromFile(const string& filename) {
mapping[2],
to_visibility);
} else if (directive == "ref") {
// Mapping ref, recurse.
// Mapping ref.
string ref_file = GetScalarValue(it->getValue());
if (ref_file.empty()) {
errs() << MappingDiag(source_manager, filename, current_node,
@ -688,6 +722,11 @@ void IncludePicker::AddMappingsFromFile(const string& filename) {
return;
}
// Add the path of the file we're currently processing
// to the search path. Allows refs to be relative to referrer.
AddMappingFileSearchPath(GetParentPath(filename));
// Recurse.
AddMappingsFromFile(ref_file);
} else {
errs() << MappingDiag(source_manager, filename, current_node,

View File

@ -50,6 +50,13 @@
#include <utility> // for pair
#include <vector> // for vector
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/MemoryBuffer.h"
namespace llvm {
class error_code;
}
namespace include_what_you_use {
using std::map;
@ -59,6 +66,10 @@ using std::string;
using std::vector;
using llvm::OwningPtr;
using llvm::MemoryBuffer;
using llvm::error_code;
class IncludePicker {
public:
enum Visibility { kUnusedVisibility, kPublic, kPrivate };
@ -76,6 +87,9 @@ class IncludePicker {
const string& includee_filepath,
const string& quoted_include_as_written);
// Add a mapping file search path.
void AddMappingFileSearchPath(const string& path);
// Add this to say "map_to re-exports everything in file map_from".
// Both map_to and map_from should be quoted includes.
void AddMapping(const string& map_from, const string& map_to);
@ -182,6 +196,11 @@ class IncludePicker {
string MaybeGetIncludeNameAsWritten(const string& includer_filepath,
const string& includee_filepath) const;
// Scan the search paths for filename. If it exists, put file contents
// in buffer. If not, return the error code.
error_code TryReadMappingFile(const string& filename,
OwningPtr<MemoryBuffer>& buffer) const;
// From symbols to includes.
IncludeMap symbol_include_map_;
@ -217,6 +236,8 @@ class IncludePicker {
// contents of friend_to_headers_map_["@\"foo/bar/.*\""].
map<string, set<string> > friend_to_headers_map_;
vector<string> mapping_file_search_path_;
// Make sure we don't do any non-const operations after finalizing.
bool has_called_finalize_added_include_lines_;
}; // class IncludePicker

View File

@ -13,6 +13,12 @@
#include "iwyu_stl_util.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/PathV2.h"
#include "llvm/Support/system_error.h"
namespace include_what_you_use {
namespace {
@ -123,6 +129,30 @@ string NormalizeFilePath(const string& path) {
return result;
}
bool IsAbsolutePath(const string& path) {
return llvm::sys::path::is_absolute(path);
}
string MakeAbsolutePath(const string& path) {
llvm::SmallString<128> absolute_path(path.c_str());
llvm::error_code error = llvm::sys::fs::make_absolute(absolute_path);
CHECK_(!error);
return absolute_path.str();
}
string MakeAbsolutePath(const string& base_path, const string& relative_path) {
llvm::SmallString<128> absolute_path(base_path.c_str());
llvm::sys::path::append(absolute_path, relative_path);
return absolute_path.str();
}
string GetParentPath(const string& path) {
llvm::StringRef parent = llvm::sys::path::parent_path(path);
return parent.str();
}
// Converts a file-path, such as /usr/include/stdio.h, to a
// quoted include, such as <stdio.h>.
string ConvertToQuotedInclude(const string& filepath) {

View File

@ -62,11 +62,20 @@ string CanonicalizeFilePath(const string& path);
// platforms.
string GetCanonicalName(string file_path);
// "Canonicals" the name on Microsoft platforms, then recursively
// removes all "./" prefixes.
string NormalizeFilePath(const string& path);
// Is path absolute?
bool IsAbsolutePath(const string& path);
// Get absolute version of path.
string MakeAbsolutePath(const string& path);
string MakeAbsolutePath(const string& base_path, const string& relative_path);
// Get the parent of path.
string GetParentPath(const string& path);
// Below, we talk 'quoted' includes. A quoted include is something
// that would be written on an #include line, complete with the <> or
// "". In the line '#include <time.h>', "<time.h>" is the quoted