Instead of include location use included filename location in

GetIncludeNameAsTyped. In case of macro use spelling location (issue #67).
This commit is contained in:
Volodymyr Sapsai 2012-06-12 20:40:02 +00:00
parent 15d0d83049
commit 1e43b5df1a
6 changed files with 125 additions and 7 deletions

View File

@ -36,6 +36,22 @@ using clang::UnresolvedMemberExpr;
namespace include_what_you_use {
// Instead of returning spelling location of 'macro_loc', obtain expansion info
// for macro at this location and return spelling location of expansion info.
SourceLocation GetMacroStartSpellingLoc(SourceLocation macro_loc) {
CHECK_(macro_loc.isValid() && macro_loc.isMacroID()
&& "Must call GetMacroStartSpellingLoc with valid macro location");
std::pair<clang::FileID, unsigned> macro_loc_info =
GlobalSourceManager()->getDecomposedLoc(macro_loc);
bool invalid = false;
const clang::SrcMgr::SLocEntry& loc_entry =
GlobalSourceManager()->getSLocEntry(macro_loc_info.first, &invalid);
CHECK_(!invalid && loc_entry.isExpansion()
&& "Should be able to obtain expansion info for macro location");
const clang::SrcMgr::ExpansionInfo& expansion_info = loc_entry.getExpansion();
return expansion_info.getSpellingLoc();
}
// This works around two bugs(?) in clang where decl->getLocation()
// can be wrong for implicit template instantiations and functions.
// (1) Consider the following code:

View File

@ -122,6 +122,10 @@ inline int GetLineNumber(clang::SourceLocation loc) {
return retval;
}
// For macro at macro_loc returns spelling location of macro start.
// macro_loc can point anywhere in macro.
clang::SourceLocation GetMacroStartSpellingLoc(clang::SourceLocation macro_loc);
// The rest of this section of the file is for returning the
// FileEntry* corresponding to a source location: the file that the
// location is in. This is a surprising amount of work.

View File

@ -36,11 +36,11 @@ using clang::FileEntry;
using clang::FileID;
using clang::MacroInfo;
using clang::Preprocessor;
using clang::PresumedLoc;
using clang::SourceLocation;
using clang::SourceRange;
using clang::Token;
using llvm::errs;
using llvm::StringRef;
using std::make_pair;
using std::string;
@ -590,6 +590,21 @@ void IwyuPreprocessorInfo::Ifndef(SourceLocation loc, const Token& id) {
FindAndReportMacroUse(GetName(id), id.getLocation());
}
void IwyuPreprocessorInfo::InclusionDirective(
SourceLocation hash_loc,
const Token& include_token,
StringRef filename,
bool is_angled,
const FileEntry* file,
SourceLocation last_include_token_loc,
StringRef search_path,
StringRef relative_path) {
if (last_include_token_loc.isMacroID())
include_filename_loc_ = GetMacroStartSpellingLoc(last_include_token_loc);
else
include_filename_loc_ = last_include_token_loc;
}
void IwyuPreprocessorInfo::FileChanged(SourceLocation loc,
FileChangeReason reason,
SrcMgr::CharacteristicKind file_type,
@ -619,8 +634,12 @@ void IwyuPreprocessorInfo::FileChanged(SourceLocation loc,
void IwyuPreprocessorInfo::FileSkipped(const FileEntry& file,
const Token &filename,
SrcMgr::CharacteristicKind file_type) {
const SourceLocation include_loc = filename.getLocation();
const string include_name_as_typed = GetIncludeNameAsTyped(include_loc);
CHECK_(include_filename_loc_.isValid() &&
"Must skip file only for actual inclusion directive");
const string include_name_as_typed =
GetIncludeNameAsTyped(include_filename_loc_);
const SourceLocation include_loc =
GetInstantiationLoc(filename.getLocation());
ERRSYM(GetFileEntry(include_loc))
<< "[ (#include) ] " << include_name_as_typed
<< " (" << GetFilePath(&file) << ")\n";
@ -633,12 +652,13 @@ void IwyuPreprocessorInfo::FileChanged_EnterFile(
SourceLocation file_beginning) {
// Get the location of the #include directive that resulted in the
// include of the file that file_beginning is in.
const PresumedLoc presumed =
GlobalSourceManager()->getPresumedLoc(file_beginning);
const SourceLocation include_loc = presumed.getIncludeLoc();
const SourceLocation include_loc = GlobalSourceManager()->getIncludeLoc(
GlobalSourceManager()->getFileID(file_beginning));
string include_name_as_typed = "";
if (!IsBuiltinOrCommandLineFile(GetFileEntry(include_loc))) {
include_name_as_typed = GetIncludeNameAsTyped(include_loc);
CHECK_(include_filename_loc_.isValid() &&
"Include from not built-in file must have inclusion directive");
include_name_as_typed = GetIncludeNameAsTyped(include_filename_loc_);
}
ERRSYM(GetFileEntry(include_loc))
<< "[ #include ] " << include_name_as_typed

View File

@ -185,6 +185,15 @@ class IwyuPreprocessorInfo : public clang::PPCallbacks,
// virtual void Else();
// virtual void Endif();
virtual void InclusionDirective(clang::SourceLocation hash_loc,
const clang::Token& include_token,
llvm::StringRef filename,
bool is_angled,
const clang::FileEntry* file,
clang::SourceLocation last_include_token_loc,
llvm::StringRef search_path,
llvm::StringRef relative_path);
virtual void FileChanged(clang::SourceLocation loc, FileChangeReason reason,
clang::SrcMgr::CharacteristicKind file_type,
clang::FileID PrevFID);
@ -331,6 +340,13 @@ class IwyuPreprocessorInfo : public clang::PPCallbacks,
// "begin_exports". There should be at most one item in this stack
// per file in the current inclusion chain..
stack<clang::SourceLocation> begin_exports_location_stack_;
// Filename spelling location in the last encountered inclusion directive.
// Should be used only in FileChanged_EnterFile, FileSkipped when
// corresponding callback is caused by inclusion directive. Don't use in
// other places because it is unclear which inclusion directive filename
// location corresponds to.
clang::SourceLocation include_filename_loc_;
};
} // namespace include_what_you_use

46
tests/computed_include.cc Normal file
View File

@ -0,0 +1,46 @@
//===--- computed_include.cc - test input file for iwyu -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests computed #includes, i.e. #includes with macros.
#include "tests/computed_include.h"
// Test macro defined in another file.
#include MACRO_INC
// Test when #include with macro from another file is skipped.
#include MACRO_INC
// Macros with angle brackets differ from macros with quotation marks: the last
// include token is '>' and '"foo.h"' respectively.
#define MACRO_ANGLED_INC <stdio.h>
#include MACRO_ANGLED_INC
// And test how such #include is skipped.
#include MACRO_ANGLED_INC
// Test macro with arguments.
#define STRINGIZE(x) #x
#include STRINGIZE(tests/computed_include.h)
IndirectClass ic;
/**** IWYU_SUMMARY
tests/computed_include.cc should add these lines:
tests/computed_include.cc should remove these lines:
- #include "tests/computed_include.h" // lines XX-XX
- #include <stdio.h> // lines XX-XX
- #include <stdio.h> // lines XX-XX
- #include "tests/indirect.h" // lines XX-XX
The full include-list for tests/computed_include.cc:
#include "tests/computed_include.h"
#include "tests/indirect.h" // for IndirectClass
***** IWYU_SUMMARY */

16
tests/computed_include.h Normal file
View File

@ -0,0 +1,16 @@
//===--- computed_include.h - test input file for iwyu --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#define MACRO_INC "tests/indirect.h"
/**** IWYU_SUMMARY
(tests/computed_include.h has correct #includes/fwd-decls)
***** IWYU_SUMMARY */