ken-matsui updated this revision to Diff 429005.
ken-matsui added a comment.
Revert the changes for errored directives
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D124726/new/
https://reviews.llvm.org/D124726
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticLexKinds.td
clang/include/clang/Lex/Preprocessor.h
clang/lib/Lex/PPDirectives.cpp
clang/test/Preprocessor/suggest-typoed-directive.c
Index: clang/test/Preprocessor/suggest-typoed-directive.c
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/suggest-typoed-directive.c
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=pre-c2x-cpp2b %s
+// RUN: %clang_cc1 -std=c2x -fsyntax-only -verify=c2x-cpp2b %s
+// RUN: %clang_cc1 -x c++ -std=c++2b -fsyntax-only -verify=c2x-cpp2b %s
+
+// id: pre-c2x-cpp2b-warning@+12 {{invalid preprocessing directive, did you mean '#if'?}}
+// ifd: pre-c2x-cpp2b-warning@+12 {{invalid preprocessing directive, did you mean '#if'?}}
+// ifde: pre-c2x-cpp2b-warning@+12 {{invalid preprocessing directive, did you mean '#ifdef'?}}
+// elf: pre-c2x-cpp2b-warning@+12 {{invalid preprocessing directive, did you mean '#elif'?}}
+// elsif: pre-c2x-cpp2b-warning@+12 {{invalid preprocessing directive, did you mean '#elif'?}}
+// elseif: pre-c2x-cpp2b-warning@+12 {{invalid preprocessing directive, did you mean '#elif'?}}
+// elfidef: not suggested to '#elifdef'
+// elfindef: not suggested to '#elifdef'
+// elfinndef: not suggested to '#elifndef'
+// els: pre-c2x-cpp2b-warning@+12 {{invalid preprocessing directive, did you mean '#else'?}}
+// endi: pre-c2x-cpp2b-warning@+12 {{invalid preprocessing directive, did you mean '#endif'?}}
+#ifdef UNDEFINED
+#id
+#ifd
+#ifde
+#elf
+#elsif
+#elseif
+#elfidef
+#elfindef
+#elfinndef
+#els
+#endi
+#endif
+// id: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#if'?}}
+// ifd: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#if'?}}
+// ifde: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#ifdef'?}}
+// elf: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#elif'?}}
+// elsif: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#elif'?}}
+// elseif: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#elif'?}}
+// elfidef: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#elifdef'?}}
+// elfindef: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#elifdef'?}}
+// elfinndef: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#elifndef'?}}
+// els: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#else'?}}
+// endi: c2x-cpp2b-warning@-12 {{invalid preprocessing directive, did you mean '#endif'?}}
+
+#ifdef UNDEFINED
+#i // no diagnostic
+#endif
+
+#if special_compiler
+#special_compiler_directive // no diagnostic
+#endif
Index: clang/lib/Lex/PPDirectives.cpp
===================================================================
--- clang/lib/Lex/PPDirectives.cpp
+++ clang/lib/Lex/PPDirectives.cpp
@@ -266,6 +266,51 @@
.Default(false);
}
+/// Find a similar string in `Candidates`.
+///
+/// \param LHS a string for a similar string in `Candidates`
+///
+/// \param Candidates the candidates to find a similar string.
+///
+/// \returns a similar string if exists. If no similar string exists,
+/// returns None.
+static Optional<StringRef> findSimilarStr(
+ StringRef LHS, const std::vector<StringRef> &Candidates) {
+ // We need to check if `Candidates` has the exact case-insensitive string
+ // because the Levenshtein distance match does not care about it.
+ for (StringRef C : Candidates) {
+ if (LHS.equals_insensitive(C)) {
+ return C;
+ }
+ }
+
+ // Keep going with the Levenshtein distance match.
+ // If the LHS size is less than 3, use the LHS size minus 1 and if not,
+ // use the LHS size divided by 3.
+ size_t Length = LHS.size();
+ size_t MaxDist = Length < 3 ? Length - 1 : Length / 3;
+
+ Optional<std::pair<StringRef, size_t>> SimilarStr = None;
+ for (StringRef C : Candidates) {
+ size_t CurDist = LHS.edit_distance(C, true);
+ if (CurDist <= MaxDist) {
+ if (!SimilarStr.hasValue()) {
+ // The first similar string found.
+ SimilarStr = {C, CurDist};
+ } else if (CurDist < SimilarStr->second) {
+ // More similar string found.
+ SimilarStr = {C, CurDist};
+ }
+ }
+ }
+
+ if (SimilarStr.hasValue()) {
+ return SimilarStr->first;
+ } else {
+ return None;
+ }
+}
+
bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
bool *ShadowFlag) {
// Missing macro name?
@@ -433,6 +478,25 @@
return BytesToSkip - LengthDiff;
}
+void Preprocessor::SuggestTypoedDirective(const Token &Tok,
+ StringRef Directive,
+ const SourceLocation &EndLoc) const {
+ std::vector<StringRef> Candidates = {
+ "if", "ifdef", "ifndef", "elif", "else", "endif"
+ };
+ if (LangOpts.C2x || LangOpts.CPlusPlus2b)
+ Candidates.insert(Candidates.end(), {"elifdef", "elifndef"});
+
+ if (Optional<StringRef> Sugg = findSimilarStr(Directive, Candidates)) {
+ CharSourceRange DirectiveRange =
+ CharSourceRange::getCharRange(Tok.getLocation(), EndLoc);
+ std::string SuggValue = Sugg.getValue().str();
+
+ auto Hint = FixItHint::CreateReplacement(DirectiveRange, "#" + SuggValue);
+ Diag(Tok, diag::warn_pp_invalid_directive) << 1 << SuggValue << Hint;
+ }
+}
+
/// SkipExcludedConditionalBlock - We just read a \#if or related directive and
/// decided that the subsequent tokens are in the \#if'd out portion of the
/// file. Lex the rest of the file, until we see an \#endif. If
@@ -556,6 +620,8 @@
CurPPLexer->pushConditionalLevel(Tok.getLocation(), /*wasskipping*/true,
/*foundnonskip*/false,
/*foundelse*/false);
+ } else {
+ SuggestTypoedDirective(Tok, Directive, endLoc);
}
} else if (Directive[0] == 'e') {
StringRef Sub = Directive.substr(1);
@@ -705,7 +771,11 @@
break;
}
}
+ } else {
+ SuggestTypoedDirective(Tok, Directive, endLoc);
}
+ } else {
+ SuggestTypoedDirective(Tok, Directive, endLoc);
}
CurPPLexer->ParsingPreprocessorDirective = false;
@@ -1182,7 +1252,8 @@
}
// If we reached here, the preprocessing token is not valid!
- Diag(Result, diag::err_pp_invalid_directive);
+ // Start suggesting if a similar directive found.
+ Diag(Result, diag::err_pp_invalid_directive) << 0;
// Read the rest of the PP line.
DiscardUntilEndOfDirective();
Index: clang/include/clang/Lex/Preprocessor.h
===================================================================
--- clang/include/clang/Lex/Preprocessor.h
+++ clang/include/clang/Lex/Preprocessor.h
@@ -2241,6 +2241,16 @@
/// Return true if an error occurs parsing the arg list.
bool ReadMacroParameterList(MacroInfo *MI, Token& LastTok);
+ /// Provide a suggestion for a typoed directive. If there is no typo, then
+ /// just skip suggesting.
+ ///
+ /// \param Tok - Token that represents the directive
+ /// \param Directive - String reference for the directive name
+ /// \param EndLoc - End location for fixit
+ void SuggestTypoedDirective(const Token &Tok,
+ StringRef Directive,
+ const SourceLocation &EndLoc) const;
+
/// We just read a \#if or related directive and decided that the
/// subsequent tokens are in the \#if'd out portion of the
/// file. Lex the rest of the file, until we see an \#endif. If \p
Index: clang/include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticLexKinds.td
+++ clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -427,7 +427,11 @@
def ext_pp_opencl_variadic_macros : Extension<
"variadic macros are a Clang extension in OpenCL">;
-def err_pp_invalid_directive : Error<"invalid preprocessing directive">;
+def err_pp_invalid_directive : Error<
+ "invalid preprocessing directive%select{|, did you mean '#%1'?}0">;
+def warn_pp_invalid_directive : Warning<
+ err_pp_invalid_directive.Text>, InGroup<DiagGroup<"unknown-directives">>;
+
def err_pp_directive_required : Error<
"%0 must be used within a preprocessing directive">;
def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -170,6 +170,13 @@
``-Wno-implicit-function-declaration``. As of C2x, support for implicit
function declarations has been removed, and the warning options will have no
effect.
+- Typoed preprocessor directives, which are in a skipped block, now can be
+ suggested as a warning (grouped under the ``-Wunknown-directives`` flag)
+ to a similar directive. To avoid providing typo correction for any other
+ directives, suggestion occurs only when a similar pre-implemented directive
+ is found. If we are not in C2x/C++2b mode, then no suggestion for `#elifdef`
+ & `#elifndef` provides.
+ Fixes `Issue 51598 <https://github.com/llvm/llvm-project/issues/51598>`_.
- ``-Wmisexpect`` warns when the branch weights collected during profiling
conflict with those added by ``llvm.expect``.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits