loplugin:cstylecast: Better heuristic...

to determine code shared between C and C++

Change-Id: I1fadf69bf9d0a2bde527b7c3f2ec4c687d70e4ae
This commit is contained in:
Stephan Bergmann 2016-07-12 17:53:16 +02:00
parent 46b52c22bf
commit ba94c97644

View File

@ -8,6 +8,7 @@
*/ */
#include <cassert> #include <cassert>
#include <limits>
#include <string> #include <string>
#include "plugin.hxx" #include "plugin.hxx"
@ -74,10 +75,6 @@ bool areSimilar(QualType type1, QualType type2) {
} }
} }
bool hasCLanguageLinkageType(FunctionDecl const * decl) {
return decl->isExternC() || decl->isInExternCContext();
}
QualType resolvePointers(QualType type) { QualType resolvePointers(QualType type) {
while (type->isPointerType()) { while (type->isPointerType()) {
type = type->getAs<PointerType>()->getPointeeType(); type = type->getAs<PointerType>()->getPointeeType();
@ -89,9 +86,7 @@ class CStyleCast:
public RecursiveASTVisitor<CStyleCast>, public loplugin::Plugin public RecursiveASTVisitor<CStyleCast>, public loplugin::Plugin
{ {
public: public:
explicit CStyleCast(InstantiationData const & data): explicit CStyleCast(InstantiationData const & data): Plugin(data) {}
Plugin(data), externCFunction(false)
{}
virtual void run() override { virtual void run() override {
if (compiler.getLangOpts().CPlusPlus) { if (compiler.getLangOpts().CPlusPlus) {
@ -99,14 +94,18 @@ public:
} }
} }
bool TraverseFunctionDecl(FunctionDecl * decl); bool TraverseLinkageSpecDecl(LinkageSpecDecl * decl);
bool VisitCStyleCastExpr(const CStyleCastExpr * expr); bool VisitCStyleCastExpr(const CStyleCastExpr * expr);
private: private:
bool isConstCast(QualType from, QualType to); bool isConstCast(QualType from, QualType to);
bool externCFunction; bool isFromCIncludeFile(SourceLocation spellingLocation) const;
bool isSharedCAndCppCode(SourceLocation location) const;
unsigned int externCContexts_ = 0;
}; };
const char * recommendedFix(clang::CastKind ck) { const char * recommendedFix(clang::CastKind ck) {
@ -118,17 +117,12 @@ const char * recommendedFix(clang::CastKind ck) {
} }
} }
bool CStyleCast::TraverseFunctionDecl(FunctionDecl * decl) { bool CStyleCast::TraverseLinkageSpecDecl(LinkageSpecDecl * decl) {
bool ext = hasCLanguageLinkageType(decl) assert(externCContexts_ != std::numeric_limits<unsigned int>::max()); //TODO
&& decl->isThisDeclarationADefinition(); ++externCContexts_;
if (ext) { bool ret = RecursiveASTVisitor::TraverseLinkageSpecDecl(decl);
assert(!externCFunction); assert(externCContexts_ != 0);
externCFunction = true; --externCContexts_;
}
bool ret = RecursiveASTVisitor::TraverseFunctionDecl(decl);
if (ext) {
externCFunction = false;
}
return ret; return ret;
} }
@ -166,6 +160,9 @@ bool CStyleCast::VisitCStyleCastExpr(const CStyleCastExpr * expr) {
perf = "const_cast"; perf = "const_cast";
} }
} }
if (isSharedCAndCppCode(expr->getLocStart())) {
return true;
}
std::string incompFrom; std::string incompFrom;
std::string incompTo; std::string incompTo;
if( expr->getCastKind() == CK_BitCast ) { if( expr->getCastKind() == CK_BitCast ) {
@ -178,15 +175,6 @@ bool CStyleCast::VisitCStyleCastExpr(const CStyleCastExpr * expr) {
incompTo = "incomplete "; incompTo = "incomplete ";
} }
} }
if (externCFunction || expr->getLocStart().isMacroID()) {
SourceLocation spellingLocation = compiler.getSourceManager().getSpellingLoc(
expr->getLocStart());
StringRef filename = compiler.getSourceManager().getFilename(spellingLocation);
// ignore C code
if ( filename.endswith(".h") ) {
return true;
}
}
if (perf == nullptr) { if (perf == nullptr) {
perf = recommendedFix(expr->getCastKind()); perf = recommendedFix(expr->getCastKind());
} }
@ -225,6 +213,28 @@ bool CStyleCast::isConstCast(QualType from, QualType to) {
return areSimilar(from, to); return areSimilar(from, to);
} }
bool CStyleCast::isFromCIncludeFile(SourceLocation spellingLocation) const {
return !compiler.getSourceManager().isInMainFile(spellingLocation)
&& (StringRef(
compiler.getSourceManager().getPresumedLoc(spellingLocation)
.getFilename())
.endswith(".h"));
}
bool CStyleCast::isSharedCAndCppCode(SourceLocation location) const {
while (compiler.getSourceManager().isMacroArgExpansion(location)) {
location = compiler.getSourceManager().getImmediateMacroCallerLoc(
location);
}
// Assume that code is intended to be shared between C and C++ if it comes
// from an include file ending in .h, and is either in an extern "C" context
// or the body of a macro definition:
return
isFromCIncludeFile(compiler.getSourceManager().getSpellingLoc(location))
&& (externCContexts_ != 0
|| compiler.getSourceManager().isMacroBodyExpansion(location));
}
loplugin::Plugin::Registration< CStyleCast > X("cstylecast"); loplugin::Plugin::Registration< CStyleCast > X("cstylecast");
} }