Commit 398b4ed8 authored by Luboš Luňák's avatar Luboš Luňák
Browse files

[clang] detect switch fallthrough marked by a comment (PR43465)

The regex can be extended if needed, but this should probably handle
most of the cases.

Differential Revision: https://reviews.llvm.org/D73852
parent 388de9df
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -1148,6 +1148,11 @@ namespace {
          continue;
        }

        if (isFollowedByFallThroughComment(LastStmt)) {
          ++AnnotatedCnt;
          continue; // Fallthrough comment, good.
        }

        ++UnannotatedCnt;
      }
      return !!UnannotatedCnt;
@@ -1208,10 +1213,41 @@ namespace {
      return nullptr;
    }

    bool isFollowedByFallThroughComment(const Stmt *Statement) {
      // Try to detect whether the fallthough is marked by a comment like
      // /*FALLTHOUGH*/.
      bool Invalid;
      const char *SourceData = S.getSourceManager().getCharacterData(
          Statement->getEndLoc(), &Invalid);
      if (Invalid)
        return false;
      const char *LineStart = SourceData;
      for (;;) {
        LineStart = strchr(LineStart, '\n');
        if (LineStart == nullptr)
          return false;
        ++LineStart; // Start of next line.
        const char *LineEnd = strchr(LineStart, '\n');
        StringRef Line(LineStart,
                       LineEnd ? LineEnd - LineStart : strlen(LineStart));
        if (LineStart == LineEnd ||
            Line.find_first_not_of(" \t\r") == StringRef::npos)
          continue; // Whitespace-only line.
        if (!FallthroughRegex.isValid())
          FallthroughRegex =
              llvm::Regex("(/\\*[ \\t]*fall(s | |-)?thr(ough|u)\\.?[ \\t]*\\*/)"
                          "|(//[ \\t]*fall(s | |-)?thr(ough|u)\\.?[ \\t]*)",
                          llvm::Regex::IgnoreCase);
        assert(FallthroughRegex.isValid());
        return FallthroughRegex.match(Line);
      }
    }

    bool FoundSwitchStatements;
    AttrStmts FallthroughStmts;
    Sema &S;
    llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
    llvm::Regex FallthroughRegex;
  };
} // anonymous namespace

+20 −0
Original line number Diff line number Diff line
// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify -Wimplicit-fallthrough %s

int fallthrough_comment(int n) {
  switch (n) {
  case 0:
    n++;
    // FALLTHROUGH
  case 1:
    n++;

    /*fall-through.*/

  case 2:
    n++;
  case 3: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '__attribute__((fallthrough));' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
    n++;
    break;
  }
  return n;
}