Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend -Wnonportable-include-path with a warning about trailing whitespace or dots #96960

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tobias-mayer
Copy link

Resolves #96064

Extends -Wnonportable-include-path with a warning about trailing whitespace or dots in include paths.

Screenshot from 2024-06-27 22-10-26

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be
notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write
permissions for the repository. In which case you can instead tag reviewers by
name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review
by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate
is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jun 27, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jun 27, 2024

@llvm/pr-subscribers-clang

Author: Tobias Mayer (tobias-mayer)

Changes

Resolves #96064

Extends -Wnonportable-include-path with a warning about trailing whitespace or dots in include paths.

Screenshot from 2024-06-27 22-10-26


Full diff: https://github.com/llvm/llvm-project/pull/96960.diff

4 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticGroups.td (+3)
  • (modified) clang/include/clang/Basic/DiagnosticLexKinds.td (+5-1)
  • (modified) clang/lib/Lex/PPDirectives.cpp (+17)
  • (added) clang/test/Preprocessor/nonportable-include-trailing-whitespace.c (+11)
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 9b37d4bd3205b..364a2387d3d50 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1535,3 +1535,6 @@ def BitIntExtension : DiagGroup<"bit-int-extension">;
 
 // Warnings about misuse of ExtractAPI options.
 def ExtractAPIMisuse : DiagGroup<"extractapi-misuse">;
+
+// Warnings about non-portable include paths
+def NonportablePath : DiagGroup<"nonportable-include-path">;
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 12d7b8c0205ee..cf6e448d8fc36 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -361,7 +361,11 @@ class NonportablePath  : Warning<
   "non-portable path to file '%0'; specified path differs in case from file"
   " name on disk">;
 def pp_nonportable_path : NonportablePath,
-  InGroup<DiagGroup<"nonportable-include-path">>;
+  InGroup<NonportablePath>;
+def pp_nonportable_path_trailing_whitespace : Warning<
+  "non-portable path to file '%0'; specified path contains trailing"
+  "whitespace or dots">,
+  InGroup<NonportablePath>;
 def pp_nonportable_system_path : NonportablePath, DefaultIgnore,
   InGroup<DiagGroup<"nonportable-system-include-path">>;
 
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index a53540b12dee6..919e3edc18032 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -2098,6 +2098,23 @@ OptionalFileEntryRef Preprocessor::LookupHeaderIncludeOrImport(
     const FileEntry *LookupFromFile, StringRef &LookupFilename,
     SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath,
     ModuleMap::KnownHeader &SuggestedModule, bool isAngled) {
+
+  // Check for trailing whitespace or dots in the include path.
+  // This must be done before looking up the file, as Windows will still
+  // find the file even if there are trailing dots or whitespace.
+  size_t TrailingPos = Filename.find_last_not_of(" .");
+  if (TrailingPos != StringRef::npos && TrailingPos < Filename.size() - 1) {
+    StringRef TrimmedFilename = Filename.rtrim(" .");
+
+    auto Hint = isAngled
+                    ? FixItHint::CreateReplacement(
+                          FilenameRange, "<" + TrimmedFilename.str() + ">")
+                    : FixItHint::CreateReplacement(
+                          FilenameRange, "\"" + TrimmedFilename.str() + "\"");
+    Diag(FilenameTok, diag::pp_nonportable_path_trailing_whitespace)
+        << Filename << TrimmedFilename << Hint;
+  }
+
   auto DiagnoseHeaderInclusion = [&](FileEntryRef FE) {
     if (LangOpts.AsmPreprocessor)
       return;
diff --git a/clang/test/Preprocessor/nonportable-include-trailing-whitespace.c b/clang/test/Preprocessor/nonportable-include-trailing-whitespace.c
new file mode 100644
index 0000000000000..6def70a59d2e1
--- /dev/null
+++ b/clang/test/Preprocessor/nonportable-include-trailing-whitespace.c
@@ -0,0 +1,11 @@
+// REQUIRES: case-insensitive-filesystem
+// RUN: %clang_cc1 -Wall %s
+
+#include "empty_file_to_include.h " // expected-warning {{non-portable path}}
+#include "empty_file_to_include.h." // expected-warning {{non-portable path}}
+#include "empty_file_to_include.h       " // expected-warning {{non-portable path}}
+#include "empty_file_to_include.h......." // expected-warning {{non-portable path}}
+#include "empty_file_to_include.h . . . " // expected-warning {{non-portable path}}
+#include "empty_file_to_include.h.. .. " // expected-warning {{non-portable path}}
+
+#include "empty_file_to_include.h" // No warning
\ No newline at end of file

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this! Please be sure to add a release note to clang/docs/ReleaseNotes.rst so users know about the improved diagnostics.

@@ -361,7 +361,11 @@ class NonportablePath : Warning<
"non-portable path to file '%0'; specified path differs in case from file"
" name on disk">;
def pp_nonportable_path : NonportablePath,
InGroup<DiagGroup<"nonportable-include-path">>;
InGroup<NonportablePath>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be nice to give the diagnostic group a different identifier (the name we expose to users is fine!) so that we don't have this weird naming conflict between the diagnostic group and the class NonportablePath definition a few lines up from here.

#include "empty_file_to_include.h . . . " // expected-warning {{non-portable path}}
#include "empty_file_to_include.h.. .. " // expected-warning {{non-portable path}}

#include "empty_file_to_include.h" // No warning
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a newline to the end of the file.

Copy link
Collaborator

@zmodem zmodem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@@ -1543,3 +1543,6 @@ def ExtractAPIMisuse : DiagGroup<"extractapi-misuse">;
// Warnings about using the non-standard extension having an explicit specialization
// with a storage class specifier.
def ExplicitSpecializationStorageClass : DiagGroup<"explicit-specialization-storage-class">;

// Warnings about non-portable include paths
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: period at the end

InGroup<NonportablePath>;
def pp_nonportable_path_trailing_whitespace : Warning<
"non-portable path to file '%0'; specified path contains trailing"
"whitespace or dots">,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless it would complicate the code too much, could we use %select{whitespace|dots} here to make the diagnostic specific to whether it's a trailing space or dot?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. How should we handle a case like #include "test.h.. .. " where we have both? Should we add a third option complaining about both or just pick whatever is the last character?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I think having both trailing dot and whitespace should be rare in practice, so just picking whichever comes last sounds fine to me.

if (TrailingPos != StringRef::npos && TrailingPos < Filename.size() - 1) {
StringRef TrimmedFilename = Filename.rtrim(" .");

auto Hint = isAngled
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're providing fixits, it would be nice to have tests for them. Look at clang/test/Parser/extra-semi.cpp for an example.

// REQUIRES: case-insensitive-filesystem
// RUN: %clang_cc1 -Wall %s

#include "empty_file_to_include.h " // expected-warning {{non-portable path}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected-warning directives require running clang with the -verify flag.

@@ -0,0 +1,11 @@
// REQUIRES: case-insensitive-filesystem
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think Mac's qualifies as a case-insensitive-filesystem, but I don't think it ignores trailing spaces/dots like Windows does(?).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure about this but I think I could remove that.
The behavior should be as follows:

  • Linux: You get the new warning and a file not found error.
  • Windows: You only get the new warning as the file is still found.
  • Mac: Warning + error just as on Linux. Case sensitivity shouldn't matter in both cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Clang could warn about trailing spaces in #include filenames
4 participants