Skip to content

Commit

Permalink
Diagnose likely typos in #include directives.
Browse files Browse the repository at this point in the history
Summary:
When someone writes

  #include "<some_file>"

or

  #include " some_file "

the compiler returns "file not fuond..." with fonts and quotes that may
make it hard to see there are excess quotes or surprising bytes in the
filename.  Assuming that files are usually logically named and start and
end with an alphanumeric character, we can check for the file's
existence by stripping the non-alphanumeric leading or trailing
characters.  If the file is found, emit a non-fatal error with a
FixItHint.

Patch by Christy Lee!

Reviewers: aaron.ballman, erikjv, rsmith

Reviewed By: rsmith

Subscribers: lebedev.ri, xbolva00, sammccall, modocache, erikjv, aaron.ballman, cfe-commits

Differential Revision: https://reviews.llvm.org/D51333

llvm-svn: 342177
  • Loading branch information
zygoloid committed Sep 13, 2018
1 parent 2f88006 commit 2ce63b4
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 2 deletions.
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/DiagnosticLexKinds.td
Expand Up @@ -422,8 +422,10 @@ def warn_pp_hdrstop_filename_ignored : Warning<
"#pragma hdrstop filename not supported, "
"/Fp can be used to specify precompiled header filename">,
InGroup<ClangClPch>;
def err_pp_file_not_found_not_fatal : Error<
def err_pp_file_not_found_angled_include_not_fatal : Error<
"'%0' file not found with <angled> include; use \"quotes\" instead">;
def err_pp_file_not_found_typo_not_fatal
: Error<"'%0' file not found, did you mean '%1'?">;
def err_pp_error_opening_file : Error<
"error opening file '%0': %1">, DefaultFatal;
def err_pp_empty_filename : Error<"empty filename">;
Expand Down
30 changes: 29 additions & 1 deletion clang/lib/Lex/PPDirectives.cpp
Expand Up @@ -1879,12 +1879,40 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped);
if (File) {
SourceRange Range(FilenameTok.getLocation(), CharEnd);
Diag(FilenameTok, diag::err_pp_file_not_found_not_fatal) <<
Diag(FilenameTok, diag::err_pp_file_not_found_angled_include_not_fatal) <<
Filename <<
FixItHint::CreateReplacement(Range, "\"" + Filename.str() + "\"");
}
}

// Check for likely typos due to leading or trailing non-isAlphanumeric
// characters
if (!File) {
StringRef OriginalFilename = Filename;
while (!isAlphanumeric(Filename.front())) {
Filename = Filename.drop_front();
}
while (!isAlphanumeric(Filename.back())) {
Filename = Filename.drop_back();
}

File = LookupFile(
FilenameLoc,
LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
LookupFrom, LookupFromFile, CurDir,
Callbacks ? &SearchPath : nullptr,
Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped);
if (File) {
SourceRange Range(FilenameTok.getLocation(), CharEnd);
auto Hint = isAngled ? FixItHint::CreateReplacement(
Range, "<" + Filename.str() + ">")
: FixItHint::CreateReplacement(
Range, "\"" + Filename.str() + "\"");
Diag(FilenameTok, diag::err_pp_file_not_found_typo_not_fatal)
<< OriginalFilename << Filename << Hint;
}
}

// If the file is still not found, just go with the vanilla diagnostic
if (!File)
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename
Expand Down
7 changes: 7 additions & 0 deletions clang/test/Preprocessor/empty_file_to_include.h
@@ -0,0 +1,7 @@

#ifndef EMPTY_FILE_TO_INCLUDE_H
#define EMPTY_FILE_TO_INCLUDE_H

// empty file

#endif
3 changes: 3 additions & 0 deletions clang/test/Preprocessor/include-likely-typo.c
@@ -0,0 +1,3 @@
// RUN: %clang_cc1 %s -verify

#include "<empty_file_to_include.h>" // expected-error {{'<empty_file_to_include.h>' file not found, did you mean 'empty_file_to_include.h'?}}

0 comments on commit 2ce63b4

Please sign in to comment.