1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
/*
* This file is part of Icecream.
*
* Based on LLVM/Clang.
*
* This file is distributed under the University of Illinois Open Source
* License.
*
*/
#include <clang/Basic/Version.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendAction.h>
#include <clang/Frontend/FrontendPluginRegistry.h>
#include <fstream>
using namespace clang;
using namespace std;
namespace IcecreamTest
{
void report( const CompilerInstance& compiler, DiagnosticsEngine::Level level, const char* txt, SourceLocation loc = SourceLocation());
class Action
: public PluginASTAction
{
public:
#if (CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR >= 6) || CLANG_VERSION_MAJOR > 3
virtual std::unique_ptr<ASTConsumer> CreateASTConsumer( CompilerInstance& compiler, StringRef infile );
#else
virtual ASTConsumer* CreateASTConsumer( CompilerInstance& compiler, StringRef infile );
#endif
virtual bool ParseArgs( const CompilerInstance& compiler, const vector< string >& args );
private:
vector< string > _args;
};
class Consumer
: public RecursiveASTVisitor< Consumer >, public ASTConsumer
{
public:
Consumer( CompilerInstance& compiler, const vector< string >& args );
bool VisitReturnStmt( const ReturnStmt* returnstmt );
virtual void HandleTranslationUnit( ASTContext& context );
private:
CompilerInstance& compiler;
};
#if (CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR >= 6) || CLANG_VERSION_MAJOR > 3
std::unique_ptr<ASTConsumer> Action::CreateASTConsumer( CompilerInstance& compiler, StringRef )
{
return unique_ptr<Consumer>( new Consumer( compiler, _args ));
}
#else
ASTConsumer* Action::CreateASTConsumer( CompilerInstance& compiler, StringRef )
{
return new Consumer( compiler, _args );
}
#endif
bool Action::ParseArgs( const CompilerInstance& /*compiler*/, const vector< string >& args )
{
_args = args;
return true;
}
Consumer::Consumer( CompilerInstance& compiler, const vector< string >& args )
: compiler( compiler )
{
// Check that the file passed as argument really exists (was included in ICECC_EXTRAFILES).
if( args.size() != 1 )
{
report( compiler, DiagnosticsEngine::Error, "Incorrect number of arguments" );
return;
}
ifstream is( args[ 0 ].c_str());
if( !is.good())
report( compiler, DiagnosticsEngine::Error, "Extra file open error" );
else
{
char buf[ 20 ];
is.getline( buf, 20 );
if( strcmp( buf, "testfile" ) != 0 )
report( compiler, DiagnosticsEngine::Error, "File contents do not match" );
else
report( compiler, DiagnosticsEngine::Warning, "Extra file check successful" );
}
}
void Consumer::HandleTranslationUnit( ASTContext& context )
{
if( context.getDiagnostics().hasErrorOccurred())
return;
TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
}
bool Consumer::VisitReturnStmt( const ReturnStmt* returnstmt )
{
// Get the expression in the return statement (see ReturnStmt API docs).
const Expr* expression = returnstmt->getRetValue();
if( expression == NULL )
return true; // plain 'return;' without expression
// Check if the expression is a bool literal (Clang uses dyn_cast<> instead of dynamic_cast<>).
if( const CXXBoolLiteralExpr* boolliteral = dyn_cast< CXXBoolLiteralExpr >( expression ))
{ // It is.
if( boolliteral->getValue() == false )
report( compiler, DiagnosticsEngine::Warning, "Icecream plugin found return false",
#if CLANG_VERSION_MAJOR >= 8
returnstmt->getBeginLoc());
#else
returnstmt->getLocStart());
#endif
}
return true;
}
void report( const CompilerInstance& compiler, DiagnosticsEngine::Level level, const char* txt, SourceLocation loc )
{
DiagnosticsEngine& engine = compiler.getDiagnostics();
#if (CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR >= 5) || CLANG_VERSION_MAJOR > 3
if( loc.isValid())
engine.Report( loc, engine.getDiagnosticIDs()->getCustomDiagID(
static_cast< DiagnosticIDs::Level >( level ), txt ));
else
engine.Report( engine.getDiagnosticIDs()->getCustomDiagID(
static_cast< DiagnosticIDs::Level >( level ), txt ));
#else
if( loc.isValid())
engine.Report( loc, engine.getCustomDiagID( level, txt ));
else
engine.Report( engine.getCustomDiagID( level, txt ));
#endif
}
} // namespace
static FrontendPluginRegistry::Add< IcecreamTest::Action > X( "icecreamtest", "Icecream test plugin" );
|