When we're emitting a diagnostic with a source location in an imported

module, provide a module import stack similar to what we would get for
an include stack, e.g.,

In module 'DependsOnModule' imported from build-fail-notes.m:4:
In module 'Module' imported from DependsOnModule.framework/Headers/DependsOnModule.h:1:
Inputs/Module.framework/Headers/Module.h:15:12: note: previous definition is here
@interface Module

<rdar://problem/12696425>

llvm-svn: 169042
This commit is contained in:
Douglas Gregor 2012-11-30 21:58:49 +00:00
parent f505d55472
commit 22103e3416
8 changed files with 151 additions and 10 deletions

View File

@ -430,6 +430,11 @@ public:
/// \returns true if an error occurred that prevented the source-location
/// entry from being loaded.
virtual bool ReadSLocEntry(int ID) = 0;
/// \brief Retrieve the module import location and name for the given ID, if
/// in fact it was loaded from a module (rather than, say, a precompiled
/// header).
virtual std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID) = 0;
};
@ -990,6 +995,21 @@ public:
return Entry.getFile().getIncludeLoc();
}
// \brief Returns the import location if the given source location is
// located within a module, or an invalid location if the source location
// is within the current translation unit.
std::pair<SourceLocation, StringRef>
getModuleImportLoc(SourceLocation Loc) const {
FileID FID = getFileID(Loc);
// Positive file IDs are in the current translation unit, and -1 is a
// placeholder.
if (FID.ID >= -1)
return std::make_pair(SourceLocation(), "");
return ExternalSLocEntries->getModuleImportLoc(FID.ID);
}
/// \brief Given a SourceLocation object \p Loc, return the expansion
/// location referenced by the ID.
SourceLocation getExpansionLoc(SourceLocation Loc) const {

View File

@ -19,6 +19,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
namespace clang {
@ -92,6 +93,9 @@ protected:
virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
const SourceManager &SM) = 0;
virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM) = 0;
virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM) = 0;
@ -103,9 +107,12 @@ protected:
private:
void emitIncludeStack(SourceLocation Loc, DiagnosticsEngine::Level Level,
const SourceManager &SM);
void emitIncludeStack(SourceLocation Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level, const SourceManager &SM);
void emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM);
void emitImportStack(SourceLocation Loc, const SourceManager &SM);
void emitImportStackRecursively(SourceLocation Loc, StringRef ModuleName,
const SourceManager &SM);
void emitModuleBuildPath(const SourceManager &SM);
void emitMacroExpansionsAndCarets(SourceLocation Loc,
DiagnosticsEngine::Level Level,
@ -154,6 +161,10 @@ public:
PresumedLoc PLoc,
const SourceManager &SM);
virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM);
virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM);

View File

@ -103,6 +103,10 @@ protected:
virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
const SourceManager &SM);
virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM);
virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM);

View File

@ -1546,6 +1546,10 @@ public:
/// \brief Read the source location entry with index ID.
virtual bool ReadSLocEntry(int ID);
/// \brief Retrieve the module import location and module name for the
/// given source manager entry ID.
virtual std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID);
/// \brief Retrieve the global submodule ID given a module and its local ID
/// number.
serialization::SubmoduleID

View File

@ -132,7 +132,7 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
// First, if this diagnostic is not in the main file, print out the
// "included from" lines.
emitIncludeStack(PLoc.getIncludeLoc(), Level, *SM);
emitIncludeStack(Loc, PLoc, Level, *SM);
}
// Next, emit the actual diagnostic message.
@ -184,21 +184,30 @@ void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
/// repeated warnings occur within the same file. It also handles the logic
/// of customizing the formatting and display of the include stack.
///
/// \param Loc The diagnostic location.
/// \param PLoc The presumed location of the diagnostic location.
/// \param Level The diagnostic level of the message this stack pertains to.
/// \param Loc The include location of the current file (not the diagnostic
/// location).
void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
const SourceManager &SM) {
SourceLocation IncludeLoc = PLoc.getIncludeLoc();
// Skip redundant include stacks altogether.
if (LastIncludeLoc == Loc)
if (LastIncludeLoc == IncludeLoc)
return;
LastIncludeLoc = Loc;
LastIncludeLoc = IncludeLoc;
if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
return;
emitIncludeStackRecursively(Loc, SM);
if (IncludeLoc.isValid())
emitIncludeStackRecursively(IncludeLoc, SM);
else {
emitModuleBuildPath(SM);
emitImportStack(Loc, SM);
}
}
/// \brief Helper to recursivly walk up the include stack and print each layer
@ -214,6 +223,16 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
if (PLoc.isInvalid())
return;
// If this source location was imported from a module, print the module
// import stack rather than the
// FIXME: We want submodule granularity here.
std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc);
if (Imported.first.isValid()) {
// This location was imported by a module. Emit the module import stack.
emitImportStackRecursively(Imported.first, Imported.second, SM);
return;
}
// Emit the other include frames first.
emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM);
@ -221,6 +240,41 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
emitIncludeLocation(Loc, PLoc, SM);
}
/// \brief Emit the module import stack associated with the current location.
void DiagnosticRenderer::emitImportStack(SourceLocation Loc,
const SourceManager &SM) {
if (Loc.isInvalid()) {
emitModuleBuildPath(SM);
return;
}
std::pair<SourceLocation, StringRef> NextImportLoc
= SM.getModuleImportLoc(Loc);
emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
}
/// \brief Helper to recursivly walk up the import stack and print each layer
/// on the way back down.
void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
StringRef ModuleName,
const SourceManager &SM) {
if (Loc.isInvalid()) {
return;
}
PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
if (PLoc.isInvalid())
return;
// Emit the other import frames first.
std::pair<SourceLocation, StringRef> NextImportLoc
= SM.getModuleImportLoc(Loc);
emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
// Emit the inclusion text/note.
emitImportLocation(Loc, PLoc, ModuleName, SM);
}
/// \brief Emit the module build path, for cases where a module is (re-)built
/// on demand.
void DiagnosticRenderer::emitModuleBuildPath(const SourceManager &SM) {
@ -407,6 +461,18 @@ void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc,
emitNote(Loc, Message.str(), &SM);
}
void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM) {
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
Message << "in module '" << ModuleName << "' imported from "
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":";
emitNote(Loc, Message.str(), &SM);
}
void
DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
PresumedLoc PLoc,

View File

@ -884,6 +884,16 @@ void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
OS << "In included file:\n";
}
void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM) {
if (DiagOpts->ShowLocation)
OS << "In module '" << ModuleName << "' imported from "
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
else
OS << "In module " << ModuleName << "':\n";
}
void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
PresumedLoc PLoc,
StringRef ModuleName,

View File

@ -1000,6 +1000,25 @@ bool ASTReader::ReadSLocEntry(int ID) {
return false;
}
std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) {
if (ID == 0)
return std::make_pair(SourceLocation(), "");
if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
Error("source location entry ID out-of-range for AST file");
return std::make_pair(SourceLocation(), "");
}
// Find which module file this entry lands in.
ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second;
if (M->Kind != MK_Module)
return std::make_pair(SourceLocation(), "");
// FIXME: Can we map this down to a particular submodule? That would be
// ideal.
return std::make_pair(M->ImportLoc, llvm::sys::path::stem(M->FileName));
}
/// \brief Find the location where the module F is imported.
SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
if (F->ImportLoc.isValid())

View File

@ -10,3 +10,10 @@
// CHECK: fatal error: could not build module 'Module'
// CHECK: fatal error: could not build module 'DependsOnModule'
// CHECK-NOT: error:
// RUN: %clang_cc1 -fmodule-cache-path %t -fmodules -F %S/Inputs %s -fdiagnostics-show-note-include-stack 2>&1 | FileCheck -check-prefix=CHECK-REDEF %s
extern int Module;
// CHECK-REDEF: In module 'DependsOnModule' imported from
// CHECK-REDEF: In module 'Module' imported from
// CHECK-REDEF: Module.h:15:12: note: previous definition is here