[clang] 7b86188 - [Diagnostic] add a warning which warns about misleading indentation
via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 25 11:52:49 PST 2019
Author: Tyker
Date: 2019-11-25T20:46:32+01:00
New Revision: 7b86188b50bf6e537fe98b326f258fbd23108b83
URL: https://github.com/llvm/llvm-project/commit/7b86188b50bf6e537fe98b326f258fbd23108b83
DIFF: https://github.com/llvm/llvm-project/commit/7b86188b50bf6e537fe98b326f258fbd23108b83.diff
LOG: [Diagnostic] add a warning which warns about misleading indentation
Summary: Add a warning for misleading indentation similar to GCC's -Wmisleading-indentation
Reviewers: aaron.ballman, xbolva00
Reviewed By: aaron.ballman, xbolva00
Subscribers: arphaman, Ka-Ka, thakis
Differential Revision: https://reviews.llvm.org/D70638
Added:
clang/test/SemaCXX/warn-misleading-indentation.cpp
Modified:
clang/include/clang/Basic/DiagnosticGroups.td
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Parse/Parser.h
clang/lib/Parse/ParseStmt.cpp
clang/test/Index/pragma-diag-reparse.c
clang/test/Misc/warning-wall.c
clang/test/Preprocessor/pragma_diagnostic_sections.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 5bfb3de86a47..666193e074f0 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -693,6 +693,7 @@ def ZeroLengthArray : DiagGroup<"zero-length-array">;
def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">;
def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">;
def Fallback : DiagGroup<"fallback">;
+def MisleadingIndentation : DiagGroup<"misleading-indentation">;
// This covers both the deprecated case (in C++98)
// and the extension case (in C++11 onwards).
@@ -884,7 +885,7 @@ def Consumed : DiagGroup<"consumed">;
// Note that putting warnings in -Wall will not disable them by default. If a
// warning should be active _only_ when -Wall is passed in, mark it as
// DefaultIgnore in addition to putting it here.
-def All : DiagGroup<"all", [Most, Parentheses, Switch, SwitchBool]>;
+def All : DiagGroup<"all", [Most, Parentheses, Switch, SwitchBool, MisleadingIndentation]>;
// Warnings that should be in clang-cl /w4.
def : DiagGroup<"CL4", [All, Extra]>;
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index c94d1b99d0e8..e6aa92eddef7 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -61,6 +61,13 @@ def warn_null_statement : Warning<
"remove unnecessary ';' to silence this warning">,
InGroup<ExtraSemiStmt>, DefaultIgnore;
+def warn_misleading_indentation : Warning<
+ "misleading indentation; %select{statement|declaration}0 is not part of "
+ "the previous '%select{if|else|for|while}1'">,
+ InGroup<MisleadingIndentation>, DefaultIgnore;
+def note_previous_statement : Note<
+ "previous statement is here">;
+
def ext_thread_before : Extension<"'__thread' before '%0'">;
def ext_keyword_as_ident : ExtWarn<
"keyword '%0' will be made available as an identifier "
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index ea1116ff7a23..edd31e3ff7e8 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2266,11 +2266,13 @@ class Parser : public CodeCompletionHandler {
return isTypeSpecifierQualifier();
}
+public:
/// isCXXDeclarationStatement - C++-specialized function that disambiguates
/// between a declaration or an expression statement, when parsing function
/// bodies. Returns true for declaration, false for expression.
bool isCXXDeclarationStatement();
+private:
/// isCXXSimpleDeclaration - C++-specialized function that disambiguates
/// between a simple-declaration or an expression-statement.
/// If during the disambiguation process a parsing error is encountered,
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 727ab75adae8..ce8aa7574b9b 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1191,6 +1191,27 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
return false;
}
+enum MisleadingStatementKind { MSK_if, MSK_else, MSK_for, MSK_while };
+
+static void
+MaybeDiagnoseMisleadingIndentation(Parser &P, SourceLocation PrevLoc,
+ SourceLocation StmtLoc,
+ MisleadingStatementKind StmtKind) {
+ Token Tok = P.getCurToken();
+ if (Tok.is(tok::semi))
+ return;
+ SourceManager &SM = P.getPreprocessor().getSourceManager();
+ unsigned PrevColNum = SM.getSpellingColumnNumber(PrevLoc);
+ unsigned CurColNum = SM.getSpellingColumnNumber(Tok.getLocation());
+ unsigned StmtColNum = SM.getSpellingColumnNumber(StmtLoc);
+ if (!Tok.isAtStartOfLine() ||
+ (PrevColNum != 0 && CurColNum != 0 && StmtColNum != 0 &&
+ PrevColNum > StmtColNum && PrevColNum == CurColNum)) {
+ P.Diag(Tok.getLocation(), diag::warn_misleading_indentation)
+ << P.isCXXDeclarationStatement() << StmtKind;
+ P.Diag(StmtLoc, diag::note_previous_statement);
+ }
+}
/// ParseIfStatement
/// if-statement: [C99 6.8.4.1]
@@ -1281,6 +1302,9 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// Pop the 'if' scope if needed.
InnerScope.Exit();
+ if (Tok.isNot(tok::kw_else))
+ MaybeDiagnoseMisleadingIndentation(*this, ThenStmtLoc, IfLoc, MSK_if);
+
// If it has an else, parse it.
SourceLocation ElseLoc;
SourceLocation ElseStmtLoc;
@@ -1313,6 +1337,9 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// Pop the 'else' scope if needed.
InnerScope.Exit();
+ if (ElseStmt.isUsable())
+ MaybeDiagnoseMisleadingIndentation(*this, ElseStmt.get()->getBeginLoc(),
+ ElseLoc, MSK_else);
} else if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteAfterIf(getCurScope());
cutOffParsing();
@@ -1491,6 +1518,10 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
InnerScope.Exit();
WhileScope.Exit();
+ if (Body.isUsable())
+ MaybeDiagnoseMisleadingIndentation(*this, Body.get()->getBeginLoc(),
+ WhileLoc, MSK_while);
+
if (Cond.isInvalid() || Body.isInvalid())
return StmtError();
@@ -1927,6 +1958,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// Leave the for-scope.
ForScope.Exit();
+ if (Body.isUsable())
+ MaybeDiagnoseMisleadingIndentation(*this, Body.get()->getBeginLoc(), ForLoc,
+ MSK_for);
+
if (Body.isInvalid())
return StmtError();
diff --git a/clang/test/Index/pragma-diag-reparse.c b/clang/test/Index/pragma-diag-reparse.c
index 71d0618d7092..aa1413cda089 100644
--- a/clang/test/Index/pragma-diag-reparse.c
+++ b/clang/test/Index/pragma-diag-reparse.c
@@ -11,6 +11,7 @@ int main (int argc, const char * argv[])
return x;
}
+#pragma clang diagnostic ignored "-Wmisleading-indentation"
void foo() { int b=0; while (b==b); }
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_FAILONERROR=1 c-index-test -test-load-source-reparse 5 local \
diff --git a/clang/test/Misc/warning-wall.c b/clang/test/Misc/warning-wall.c
index fadcceefe297..2b27b67eafa1 100644
--- a/clang/test/Misc/warning-wall.c
+++ b/clang/test/Misc/warning-wall.c
@@ -90,6 +90,7 @@ CHECK-NEXT: -Wparentheses-equality
CHECK-NEXT: -Wdangling-else
CHECK-NEXT: -Wswitch
CHECK-NEXT: -Wswitch-bool
+CHECK-NEXT: -Wmisleading-indentation
CHECK-NOT:-W
diff --git a/clang/test/Preprocessor/pragma_diagnostic_sections.cpp b/clang/test/Preprocessor/pragma_diagnostic_sections.cpp
index b680fae5b993..2bba7595a810 100644
--- a/clang/test/Preprocessor/pragma_diagnostic_sections.cpp
+++ b/clang/test/Preprocessor/pragma_diagnostic_sections.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wall -Wunused-macros -Wunused-parameter -Wno-uninitialized -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wall -Wunused-macros -Wunused-parameter -Wno-uninitialized -Wno-misleading-indentation -verify %s
// rdar://8365684
struct S {
diff --git a/clang/test/SemaCXX/warn-misleading-indentation.cpp b/clang/test/SemaCXX/warn-misleading-indentation.cpp
new file mode 100644
index 000000000000..fef83f1e0277
--- /dev/null
+++ b/clang/test/SemaCXX/warn-misleading-indentation.cpp
@@ -0,0 +1,184 @@
+// RUN: %clang_cc1 -x c -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wmisleading-indentation -DWITH_WARN %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -Wall -Wno-unused -DWITH_WARN -DCXX17 %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -Wall -Wno-unused -Wno-misleading-indentation -DCXX17 %s
+
+#ifndef WITH_WARN
+// expected-no-diagnostics
+#endif
+
+void f0(int i) {
+ if (i)
+#ifdef WITH_WARN
+// expected-note at -2 {{here}}
+#endif
+ i = i + 1;
+ int x = 0;
+#ifdef WITH_WARN
+// expected-warning at -2 {{misleading indentation; declaration is not part of the previous 'if'}}
+#endif
+ return;
+#ifdef CXX17
+ if constexpr (false)
+#ifdef WITH_WARN
+// expected-note at -2 {{here}}
+#endif
+ i = 0;
+ i += 1;
+#ifdef WITH_WARN
+// expected-warning at -2 {{misleading indentation; statement is not part of the previous 'if'}}
+#endif
+#endif
+}
+
+void f1(int i) {
+ for (;i;)
+#ifdef WITH_WARN
+// expected-note at -2 {{here}}
+#endif
+ i = i + 1;
+ i *= 2;
+#ifdef WITH_WARN
+// expected-warning at -2 {{misleading indentation; statement is not part of the previous 'for'}}
+#endif
+ return;
+}
+
+void f2(int i) {
+ while (i)
+#ifdef WITH_WARN
+// expected-note at -2 {{here}}
+#endif
+ i = i + 1; i *= 2;
+#ifdef WITH_WARN
+// expected-warning at -2 {{misleading indentation; statement is not part of the previous 'while'}}
+#endif
+ return;
+}
+
+void f3(int i) {
+ if (i)
+ i = i + 1;
+ else
+#ifdef WITH_WARN
+// expected-note at -2 {{here}}
+#endif
+ i *= 2;
+ const int x = 0;
+#ifdef WITH_WARN
+// expected-warning at -2 {{misleading indentation; declaration is not part of the previous 'else'}}
+#endif
+}
+
+#ifdef CXX17
+struct Range {
+ int *begin() {return nullptr;}
+ int *end() {return nullptr;}
+};
+#endif
+
+void f4(int i) {
+ if (i)
+ i *= 2;
+ return;
+ if (i)
+ i *= 2;
+ ;
+ if (i)
+#ifdef WITH_WARN
+// expected-note at -2 {{here}}
+#endif
+ i *= 2;
+ typedef int Int;
+#ifdef WITH_WARN
+// expected-warning at -2 {{misleading indentation; declaration is not part of the previous 'if'}}
+#endif
+#ifdef CXX17
+ Range R;
+ for (auto e : R)
+#ifdef WITH_WARN
+// expected-note at -2 {{here}}
+#endif
+ i *= 2;
+ using Int2 = int;
+#ifdef WITH_WARN
+// expected-warning at -2 {{misleading indentation; declaration is not part of the previous 'for'}}
+#endif
+#endif
+}
+
+int bar(void);
+
+int foo(int* dst)
+{
+ if (dst)
+ return
+ bar();
+ if (dst)
+ dst = dst + \
+ bar();
+ return 0;
+}
+
+// No diagnostics from GCC on this
+void g(int i) {
+ if (1)
+ i = 2;
+ else
+ if (i == 3)
+ i = 4;
+ i = 5;
+}
+
+// Or this
+#define TEST i = 5
+void g0(int i) {
+ if (1)
+ i = 2;
+ else
+ i = 5;
+ TEST;
+}
+
+void g1(int i) {
+ if (1)
+ i = 2;
+ else
+#ifdef WITH_WARN
+// expected-note at -2 {{here}}
+#endif
+ if (i == 3)
+ i = 4;
+ i = 5;
+#ifdef WITH_WARN
+// expected-warning at -2 {{misleading indentation; statement is not part of the previous 'else'}}
+#endif
+}
+
+void g2(int i) {
+ if (1)
+ i = 2;
+ else
+#ifdef WITH_WARN
+// expected-note at -2 {{here}}
+#endif
+ if (i == 3)
+ {i = 4;}
+ i = 5;
+#ifdef WITH_WARN
+// expected-warning at -2 {{misleading indentation; statement is not part of the previous 'else'}}
+#endif
+}
+
+void g6(int i) {
+ if (1)
+ if (i == 3)
+#ifdef WITH_WARN
+// expected-note at -2 {{here}}
+#endif
+ i = 4;
+ i = 5;
+#ifdef WITH_WARN
+// expected-warning at -2 {{misleading indentation; statement is not part of the previous 'if'}}
+#endif
+}
More information about the cfe-commits
mailing list