aganea created this revision.
aganea added reviewers: hans, thakis, rsmith.
aganea added a project: clang.
Previously, `-fdiagnostics-absolute-paths` did not have an effect in some
cases, for example: when using relative include paths, or relative CPP paths,
or `--show-includes`, or `-E` or displaying notes. We have a peculiar use-case
on our end with Fastbuild, where all this was exposed: CPP files are being are
preprocessed on one PC, then compiled on another PC (which doesn't have the
source-code); then the compiler's stdout is displayed on the first PC.
Repository:
rC Clang
https://reviews.llvm.org/D63648
Files:
include/clang/Frontend/TextDiagnostic.h
lib/Frontend/HeaderIncludeGen.cpp
lib/Frontend/PrintPreprocessedOutput.cpp
lib/Frontend/TextDiagnostic.cpp
test/Frontend/absolute-paths.c
test/Modules/build-fail-notes.m
test/Preprocessor/pp-modules.c
Index: test/Preprocessor/pp-modules.c
===================================================================
--- test/Preprocessor/pp-modules.c
+++ test/Preprocessor/pp-modules.c
@@ -13,3 +13,30 @@
#include "pp-modules.h" // CHECK: # 1 "{{.*}}pp-modules.h" 1
// CHECK: #pragma clang module import Module /* clang -E: implicit import for #include <Module/Module.h> */{{$}}
// CHECK: # 14 "{{.*}}pp-modules.c" 2
+
+// Also test path canonicalization
+// RUN: cd %S
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c pp-modules.c -F %S/../Modules/Inputs -E -o - | FileCheck -check-prefix=CHECK-RELATIVE %s
+
+// CHECK-RELATIVE: # 1 "pp-modules.c"
+// CHECK-RELATIVE-NEXT: # 1 "<built-in>" 1
+// CHECK-RELATIVE-NEXT: # 1 "<built-in>" 3
+// CHECK-RELATIVE-NEXT: # {{[0-9]+}} "<built-in>" 3
+// CHECK-RELATIVE-NEXT: # 1 "<command line>" 1
+// CHECK-RELATIVE-NEXT: # 1 "<built-in>" 2
+// CHECK-RELATIVE-NEXT: # 1 "pp-modules.c" 2
+// CHECK-RELATIVE: # 1 "./pp-modules.h" 1
+// CHECK-RELATIVE: # 14 "pp-modules.c" 2
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c pp-modules.c -F %S/../Modules/Inputs -E -o - -fdiagnostics-absolute-paths | FileCheck -check-prefix=CHECK-ABSOLUTE %s
+
+// CHECK-ABSOLUTE: # 1 "{{.+(/|\\\\)test(/|\\\\)Preprocessor(/|\\\\)}}pp-modules.c"
+// CHECK-ABSOLUTE-NEXT: # 1 "<built-in>" 1
+// CHECK-ABSOLUTE-NEXT: # 1 "<built-in>" 3
+// CHECK-ABSOLUTE-NEXT: # {{[0-9]+}} "<built-in>" 3
+// CHECK-ABSOLUTE-NEXT: # 1 "<command line>" 1
+// CHECK-ABSOLUTE-NEXT: # 1 "<built-in>" 2
+// CHECK-ABSOLUTE-NEXT: # 1 "{{.+(/|\\\\)test(/|\\\\)Preprocessor(/|\\\\)}}pp-modules.c" 2
+
+// CHECK-ABSOLUTE: # 1 "{{.+(/|\\\\)test(/|\\\\)Preprocessor(/|\\\\)}}pp-modules.h" 1
+// CHECK-ABSOLUTE: # 14 "{{.+(/|\\\\)test(/|\\\\)Preprocessor(/|\\\\)}}pp-modules.c" 2
Index: test/Modules/build-fail-notes.m
===================================================================
--- test/Modules/build-fail-notes.m
+++ test/Modules/build-fail-notes.m
@@ -29,3 +29,16 @@
// CHECK-SDIAG: DependsOnModule.h:1:10: fatal: could not build module 'Module'
// CHECK-SDIAG: build-fail-notes.m:4:9: note: while building module 'DependsOnModule' imported from
+// Also test path canonicalization
+// RUN: cd %S
+// RUN: not %clang_cc1 -Wincomplete-umbrella -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F Inputs -DgetModuleVersion="epic fail" -serialize-diagnostic-file %t/tmp.diag build-fail-notes.m 2>&1 -fdiagnostics-show-note-include-stack | FileCheck -check-prefix=CHECK-RELATIVE %s
+// CHECK-RELATIVE: While building module 'DependsOnModule' imported from build-fail-notes.m:4:
+// CHECK-RELATIVE-NEXT: While building module 'Module' imported from Inputs{{/|\\}}DependsOnModule.framework{{/|\\}}Headers{{/|\\}}DependsOnModule.h:1:
+// CHECK-RELATIVE-NEXT: In file included from <module-includes>:1:
+// CHECK-RELATIVE-NEXT: Inputs{{/|\\}}Module.framework{{/|\\}}Headers{{/|\\}}Module.h:9:13: error: expected ';' after top level declarator
+
+// RUN: not %clang_cc1 -Wincomplete-umbrella -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F Inputs -DgetModuleVersion="epic fail" -serialize-diagnostic-file %t/tmp.diag build-fail-notes.m 2>&1 -fdiagnostics-show-note-include-stack -fdiagnostics-absolute-paths | FileCheck -check-prefix=CHECK-ABSOLUTE %s
+// CHECK-ABSOLUTE: While building module 'DependsOnModule' imported from {{.+(/|\\)test(/|\\)Modules(/|\\)}}build-fail-notes.m:4:
+// CHECK-ABSOLUTE-NEXT: While building module 'Module' imported from {{.+(/|\\)test(/|\\)Modules(/|\\)Inputs(/|\\)DependsOnModule.framework(/|\\)Headers(/|\\)}}DependsOnModule.h:1:
+// CHECK-ABSOLUTE-NEXT: In file included from {{.+(/|\\)test(/|\\)Modules(/|\\)}}<module-includes>:1:
+// CHECK-ABSOLUTE-NEXT: {{.+(/|\\)test(/|\\)Modules(/|\\)Inputs(/|\\)Module.framework(/|\\)Headers(/|\\)}}Module.h:9:13: error: expected ';' after top level declarator
Index: test/Frontend/absolute-paths.c
===================================================================
--- test/Frontend/absolute-paths.c
+++ test/Frontend/absolute-paths.c
@@ -15,3 +15,19 @@
int g() {}
// NORMAL: non-existant.c:123:10: warning: control reaches end of non-void function
// ABSOLUTE: non-existant.c:123:10: warning: control reaches end of non-void function
+
+// Also test with relative include paths
+// RUN: cd %S
+// RUN: %clang_cc1 -fsyntax-only -I Inputs --show-includes absolute-paths.c 2>&1 | FileCheck -check-prefix=RELATIVE %s
+
+// RELATIVE: Note: including file: Inputs{{/|\\}}absolute-paths.h
+// RELATIVE-NEXT: In file included from absolute-paths.c:4:
+// RELATIVE-NEXT: Inputs{{/|\\}}absolute-paths.h:3:1: warning: control reaches end of non-void function
+// RELATIVE: non-existant.c:123:10: warning: control reaches end of non-void function
+
+// RUN: %clang_cc1 -fsyntax-only -I Inputs --show-includes -fdiagnostics-absolute-paths absolute-paths.c 2>&1 | FileCheck -check-prefix=RELATIVE2 %s
+
+// RELATIVE2: Note: including file: {{.+(/|\\)test(/|\\)Frontend(/|\\)Inputs(/|\\)}}absolute-paths.h
+// RELATIVE2-NEXT: In file included from {{.+(/|\\)test(/|\\)Frontend(/|\\)}}absolute-paths.c:4:
+// RELATIVE2-NEXT: {{.+(/|\\)test(/|\\)Frontend(/|\\)Inputs(/|\\)}}absolute-paths.h:3:1: warning: control reaches end of non-void function
+// RELATIVE2: {{.+(/|\\)test(/|\\)Frontend(/|\\)}}non-existant.c:123:10: warning: control reaches end of non-void function
Index: lib/Frontend/TextDiagnostic.cpp
===================================================================
--- lib/Frontend/TextDiagnostic.cpp
+++ lib/Frontend/TextDiagnostic.cpp
@@ -759,46 +759,67 @@
OS << '\n';
}
-void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
- SmallVector<char, 128> AbsoluteFilename;
- if (DiagOpts->AbsolutePath) {
- const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
- llvm::sys::path::parent_path(Filename));
- if (Dir) {
- // We want to print a simplified absolute path, i. e. without "dots".
- //
- // The hardest part here are the paths like "<part1>/<link>/../<part2>".
- // On Unix-like systems, we cannot just collapse "<link>/..", because
- // paths are resolved sequentially, and, thereby, the path
- // "<part1>/<part2>" may point to a different location. That is why
- // we use FileManager::getCanonicalName(), which expands all indirections
- // with llvm::sys::fs::real_path() and caches the result.
- //
- // On the other hand, it would be better to preserve as much of the
- // original path as possible, because that helps a user to recognize it.
- // real_path() expands all links, which sometimes too much. Luckily,
- // on Windows we can just use llvm::sys::path::remove_dots(), because,
- // on that system, both aforementioned paths point to the same place.
+StringRef
+TextDiagnostic::canonicalizePath(StringRef Filename, const SourceManager &SM,
+ SmallVectorImpl<char> &AbsolutePath) {
+ DiagnosticOptions &Opts = SM.getDiagnostics().getDiagnosticOptions();
+ if (!Opts.AbsolutePath)
+ return Filename;
+
+ SmallString<4096> Path(Filename);
+ SM.getFileManager().makeAbsolutePath(Path);
+
+ const DirectoryEntry *Dir =
+ SM.getFileManager().getDirectory(llvm::sys::path::parent_path(Path));
+ if (!Dir)
+ return Filename;
+
+ // FIXME: convert to an enum
+ if (Filename == "<command line>" || Filename == "<scratch space>" ||
+ Filename == "<built-in>")
+ return Filename;
+
+ // We want to print a simplified absolute path, i. e. without "dots".
+ //
+ // The hardest part here are the paths like "<part1>/<link>/../<part2>".
+ // On Unix-like systems, we cannot just collapse "<link>/..", because
+ // paths are resolved sequentially, and, thereby, the path
+ // "<part1>/<part2>" may point to a different location. That is why
+ // we use FileManager::getCanonicalName(), which expands all indirections
+ // with llvm::sys::fs::real_path() and caches the result.
+ //
+ // On the other hand, it would be better to preserve as much of the
+ // original path as possible, because that helps a user to recognize it.
+ // real_path() expands all links, which sometimes too much. Luckily,
+ // on Windows we can just use llvm::sys::path::remove_dots(), because,
+ // on that system, both aforementioned paths point to the same place.
#ifdef _WIN32
- SmallString<4096> DirName = Dir->getName();
- llvm::sys::fs::make_absolute(DirName);
- llvm::sys::path::native(DirName);
- llvm::sys::path::remove_dots(DirName, /* remove_dot_dot */ true);
+ SmallString<4096> DirName = Dir->getName();
+ llvm::sys::fs::make_absolute(DirName);
+ llvm::sys::path::native(DirName);
+ llvm::sys::path::remove_dots(DirName, /* remove_dot_dot */ true);
#else
- StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
+ StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
#endif
- llvm::sys::path::append(AbsoluteFilename, DirName,
- llvm::sys::path::filename(Filename));
- Filename = StringRef(AbsoluteFilename.data(), AbsoluteFilename.size());
- }
- }
+ llvm::sys::path::append(AbsolutePath, DirName,
+ llvm::sys::path::filename(Filename));
+ return StringRef(AbsolutePath.data(), AbsolutePath.size());
+}
+
+std::string TextDiagnostic::emitFilename(StringRef Filename,
+ const SourceManager &SM) {
+ SmallString<128> AbsolutePath;
+ return canonicalizePath(Filename, SM, AbsolutePath);
+}
- OS << Filename;
+std::string TextDiagnostic::emitFilename(FullSourceLoc Loc, PresumedLoc PLoc) {
+ SmallString<128> AbsolutePath;
+ return canonicalizePath(PLoc.getFilename(), Loc.getManager(), AbsolutePath);
}
/// Print out the file/line/column information and include trace.
///
-/// This method handlen the emission of the diagnostic location information.
+/// This method handles the emission of the diagnostic location information.
/// This includes extracting as much location information as is present for
/// the diagnostic and printing it, as well as any include stack or source
/// ranges necessary.
@@ -811,7 +832,7 @@
if (FID.isValid()) {
const FileEntry *FE = Loc.getFileEntry();
if (FE && FE->isValid()) {
- emitFilename(FE->getName(), Loc.getManager());
+ OS << emitFilename(FE->getName(), Loc.getManager());
OS << ": ";
}
}
@@ -825,7 +846,7 @@
if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
- emitFilename(PLoc.getFilename(), Loc.getManager());
+ OS << emitFilename(Loc, PLoc);
switch (DiagOpts->getFormat()) {
case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
case DiagnosticOptions::MSVC: OS << '(' << LineNo; break;
@@ -905,7 +926,8 @@
void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
if (DiagOpts->ShowLocation && PLoc.isValid())
- OS << "In file included from " << PLoc.getFilename() << ':'
+ OS << "In file included from "
+ << emitFilename(Loc, PLoc) << ':'
<< PLoc.getLine() << ":\n";
else
OS << "In included file:\n";
@@ -915,7 +937,8 @@
StringRef ModuleName) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "In module '" << ModuleName << "' imported from "
- << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
+ << emitFilename(Loc, PLoc) << ':'
+ << PLoc.getLine() << ":\n";
else
OS << "In module '" << ModuleName << "':\n";
}
@@ -925,7 +948,8 @@
StringRef ModuleName) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "While building module '" << ModuleName << "' imported from "
- << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
+ << emitFilename(Loc, PLoc) << ':'
+ << PLoc.getLine() << ":\n";
else
OS << "While building module '" << ModuleName << "':\n";
}
@@ -1351,7 +1375,7 @@
break;
OS << "fix-it:\"";
- OS.write_escaped(PLoc.getFilename());
+ OS.write_escaped(emitFilename(PLoc.getFilename(), SM));
OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
<< ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
<< '-' << SM.getLineNumber(EInfo.first, EInfo.second)
Index: lib/Frontend/PrintPreprocessedOutput.cpp
===================================================================
--- lib/Frontend/PrintPreprocessedOutput.cpp
+++ lib/Frontend/PrintPreprocessedOutput.cpp
@@ -11,11 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/Utils.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
+#include "clang/Frontend/TextDiagnostic.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Pragma.h"
@@ -27,6 +28,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
+
using namespace clang;
/// PrintMacroDefinition - Print a macro definition in a form that will be
@@ -286,7 +288,11 @@
CurLine = NewLine;
CurFilename.clear();
- CurFilename += UserLoc.getFilename();
+
+ SmallString<128> AbsolutePath;
+ CurFilename +=
+ TextDiagnostic::canonicalizePath(UserLoc.getFilename(), SM, AbsolutePath);
+
FileType = NewFileType;
if (DisableLineMarkers) {
Index: lib/Frontend/HeaderIncludeGen.cpp
===================================================================
--- lib/Frontend/HeaderIncludeGen.cpp
+++ lib/Frontend/HeaderIncludeGen.cpp
@@ -6,13 +6,15 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/DependencyOutputOptions.h"
-#include "clang/Frontend/Utils.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/DependencyOutputOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnostic.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+
using namespace clang;
namespace {
@@ -173,7 +175,9 @@
// "<command line>" and "<built-in>" in a bunch of places.
if (ShowHeader && Reason == PPCallbacks::EnterFile &&
UserLoc.getFilename() != StringRef("<command line>")) {
- PrintHeaderInfo(OutputFile, UserLoc.getFilename(), ShowDepth, IncludeDepth,
- MSStyle);
+ SmallString<128> AbsolutePath;
+ StringRef Filename = TextDiagnostic::canonicalizePath(UserLoc.getFilename(),
+ SM, AbsolutePath);
+ PrintHeaderInfo(OutputFile, Filename, ShowDepth, IncludeDepth, MSStyle);
}
}
Index: include/clang/Frontend/TextDiagnostic.h
===================================================================
--- include/clang/Frontend/TextDiagnostic.h
+++ include/clang/Frontend/TextDiagnostic.h
@@ -73,6 +73,10 @@
StringRef Message, unsigned CurrentColumn,
unsigned Columns, bool ShowColors);
+ /// Canonicalize a file path iff we want it absolute
+ static StringRef canonicalizePath(StringRef Filename, const SourceManager &SM,
+ SmallVectorImpl<char> &AbsolutePath);
+
protected:
void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level, StringRef Message,
@@ -98,7 +102,8 @@
StringRef ModuleName) override;
private:
- void emitFilename(StringRef Filename, const SourceManager &SM);
+ static std::string emitFilename(StringRef Filename, const SourceManager &SM);
+ static std::string emitFilename(FullSourceLoc Loc, PresumedLoc PLoc);
void emitSnippetAndCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange> &Ranges,
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits