aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/AnalysisBasedWarnings.cpp
diff options
context:
space:
mode:
authorAlexander Kornienko <alexfh@google.com>2012-09-28 22:24:03 +0000
committerAlexander Kornienko <alexfh@google.com>2012-09-28 22:24:03 +0000
commit66da0abf7ab7cd449bb1d5134b2ef97d9d34d812 (patch)
tree0db2b50ad18241bdfb606f50a3228613ed024137 /lib/Sema/AnalysisBasedWarnings.cpp
parent3437daad71d8694d4ddd25418751f2763c0f8979 (diff)
Compatibility macro detection for the -Wimplicit-fallthrough diagnostic.
Summary: When issuing a diagnostic message for the -Wimplicit-fallthrough diagnostics, always try to find the latest macro, defined at the point of fallthrough, which is immediately expanded to "[[clang::fallthrough]]", and use it's name instead of the actual sequence. Known issues: * uses PP.getSpelling() to compare macro definition with a string (anyone can suggest a convenient way to fill a token array, or maybe lex it in runtime?); * this can be generalized and used in other similar cases, any ideas where it should reside then? Reviewers: doug.gregor, rsmith Reviewed By: rsmith CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D50 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164858 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp67
1 files changed, 66 insertions, 1 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index bc25c0a554..ec500a06c3 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -36,6 +36,7 @@
#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -678,6 +679,61 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
return true;
}
+/// \brief Stores token information for comparing actual tokens with
+/// predefined values. Only handles simple tokens and identifiers.
+class TokenValue {
+ tok::TokenKind Kind;
+ IdentifierInfo *II;
+
+public:
+ TokenValue(tok::TokenKind Kind) : Kind(Kind), II(0) {
+ assert(Kind != tok::raw_identifier && "Raw identifiers are not supported.");
+ assert(Kind != tok::identifier &&
+ "Identifiers should be created by TokenValue(IdentifierInfo *)");
+ assert(!tok::isLiteral(Kind) && "Literals are not supported.");
+ assert(!tok::isAnnotation(Kind) && "Annotations are not supported.");
+ }
+ TokenValue(IdentifierInfo *II) : Kind(tok::identifier), II(II) {}
+ bool operator==(const Token &Tok) const {
+ return Tok.getKind() == Kind &&
+ (!II || II == Tok.getIdentifierInfo());
+ }
+};
+
+/// \brief Compares macro tokens with a specified token value sequence.
+static bool MacroDefinitionEquals(const MacroInfo *MI,
+ llvm::ArrayRef<TokenValue> Tokens) {
+ return Tokens.size() == MI->getNumTokens() &&
+ std::equal(Tokens.begin(), Tokens.end(), MI->tokens_begin());
+}
+
+static std::string GetSuitableSpelling(Preprocessor &PP, SourceLocation L,
+ llvm::ArrayRef<TokenValue> Tokens,
+ const char *Spelling) {
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation BestLocation;
+ std::string BestSpelling = Spelling;
+ for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
+ I != E; ++I) {
+ if (!I->second->isObjectLike())
+ continue;
+ const MacroInfo *MI = I->second->findDefinitionAtLoc(L, SM);
+ if (!MI)
+ continue;
+ if (!MacroDefinitionEquals(MI, Tokens))
+ continue;
+ SourceLocation Location = I->second->getDefinitionLoc();
+ // Choose the macro defined latest.
+ if (BestLocation.isInvalid() ||
+ (Location.isValid() &&
+ SM.isBeforeInTranslationUnit(BestLocation, Location))) {
+ BestLocation = Location;
+ BestSpelling = I->first->getName();
+ }
+ }
+ return BestSpelling;
+}
+
namespace {
class FallthroughMapper : public RecursiveASTVisitor<FallthroughMapper> {
public:
@@ -852,8 +908,17 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
if (S.getLangOpts().CPlusPlus0x) {
const Stmt *Term = B.getTerminator();
if (!(B.empty() && Term && isa<BreakStmt>(Term))) {
+ Preprocessor &PP = S.getPreprocessor();
+ TokenValue Tokens[] = {
+ tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
+ tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
+ tok::r_square, tok::r_square
+ };
+ std::string AnnotationSpelling = GetSuitableSpelling(
+ PP, L, Tokens, "[[clang::fallthrough]]");
S.Diag(L, diag::note_insert_fallthrough_fixit) <<
- FixItHint::CreateInsertion(L, "[[clang::fallthrough]]; ");
+ AnnotationSpelling <<
+ FixItHint::CreateInsertion(L, AnnotationSpelling + "; ");
}
}
S.Diag(L, diag::note_insert_break_fixit) <<