diff options
author | Alexander Kornienko <alexfh@google.com> | 2012-09-28 22:24:03 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2012-09-28 22:24:03 +0000 |
commit | 66da0abf7ab7cd449bb1d5134b2ef97d9d34d812 (patch) | |
tree | 0db2b50ad18241bdfb606f50a3228613ed024137 /lib/Sema/AnalysisBasedWarnings.cpp | |
parent | 3437daad71d8694d4ddd25418751f2763c0f8979 (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.cpp | 67 |
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) << |