2013-09-21 14:42:35 +01:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2012-10-05 18:17:13 +02:00
|
|
|
/*
|
|
|
|
* This file is part of the LibreOffice project.
|
|
|
|
*
|
|
|
|
* Based on LLVM/Clang.
|
|
|
|
*
|
|
|
|
* This file is distributed under the University of Illinois Open Source
|
|
|
|
* License. See LICENSE.TXT for details.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2012-10-15 15:36:25 +02:00
|
|
|
#include "plugin.hxx"
|
2012-10-05 18:17:13 +02:00
|
|
|
|
2014-01-27 13:09:20 +01:00
|
|
|
#include <cassert>
|
2016-09-22 08:50:43 +02:00
|
|
|
#include <string>
|
2014-01-27 13:09:20 +01:00
|
|
|
|
2012-10-15 15:36:25 +02:00
|
|
|
#include <clang/Basic/FileManager.h>
|
2013-08-14 16:39:11 +02:00
|
|
|
#include <clang/Lex/Lexer.h>
|
2012-10-05 18:17:13 +02:00
|
|
|
|
2013-02-02 16:35:47 +01:00
|
|
|
#include "pluginhandler.hxx"
|
2012-10-09 14:50:19 +02:00
|
|
|
|
2013-02-02 18:34:12 +01:00
|
|
|
/*
|
|
|
|
Base classes for plugin actions.
|
|
|
|
*/
|
2012-10-05 18:17:13 +02:00
|
|
|
namespace loplugin
|
|
|
|
{
|
|
|
|
|
2014-01-27 13:09:20 +01:00
|
|
|
Plugin::Plugin( const InstantiationData& data )
|
2014-02-20 19:47:01 +01:00
|
|
|
: compiler( data.compiler ), handler( data.handler ), name( data.name )
|
2012-10-09 16:27:25 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-02-14 15:54:59 +01:00
|
|
|
DiagnosticBuilder Plugin::report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc ) const
|
2013-02-02 19:31:24 +01:00
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
return handler.report( level, name, message, compiler, loc );
|
2012-10-09 16:27:25 +02:00
|
|
|
}
|
|
|
|
|
2012-10-09 16:39:49 +02:00
|
|
|
bool Plugin::ignoreLocation( SourceLocation loc )
|
|
|
|
{
|
2013-03-21 16:42:10 +01:00
|
|
|
SourceLocation expansionLoc = compiler.getSourceManager().getExpansionLoc( loc );
|
|
|
|
if( compiler.getSourceManager().isInSystemHeader( expansionLoc ))
|
2013-01-03 20:15:21 +01:00
|
|
|
return true;
|
2013-03-21 16:42:10 +01:00
|
|
|
const char* bufferName = compiler.getSourceManager().getPresumedLoc( expansionLoc ).getFilename();
|
2014-01-10 11:07:55 +01:00
|
|
|
if( bufferName == NULL
|
2016-04-13 23:14:26 +02:00
|
|
|
|| strncmp( bufferName, SRCDIR "/external/", strlen( SRCDIR "/external/" )) == 0 )
|
2013-01-03 20:15:21 +01:00
|
|
|
return true;
|
2016-09-22 08:50:43 +02:00
|
|
|
if( strncmp( bufferName, WORKDIR, strlen( WORKDIR )) == 0 )
|
|
|
|
{
|
|
|
|
// workdir/CustomTarget/vcl/unx/kde4/tst_exclude_socket_notifiers.moc
|
|
|
|
// includes
|
|
|
|
// "../../../../../vcl/unx/kde4/tst_exclude_socket_notifiers.hxx",
|
|
|
|
// making the latter file erroneously match here; so strip any ".."
|
|
|
|
// segments:
|
|
|
|
if (strstr(bufferName, "/..") == nullptr) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
std::string s(bufferName);
|
|
|
|
for (std::string::size_type i = 0;;) {
|
|
|
|
i = s.find("/.", i);
|
|
|
|
if (i == std::string::npos) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i + 2 == s.length() || s[i + 2] == '/') {
|
|
|
|
s.erase(i, 2); // [AAA]/.[/CCC] -> [AAA][/CCC]
|
|
|
|
} else if (s[i + 2] == '.'
|
|
|
|
&& (i + 3 == s.length() || s[i + 3] == '/'))
|
|
|
|
{
|
|
|
|
if (i == 0) { // /..[/CCC] -> /..[/CCC]
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
auto j = s.rfind('/', i - 1);
|
|
|
|
if (j == std::string::npos) {
|
|
|
|
// BBB/..[/CCC] -> BBB/..[/CCC] (instead of BBB/../CCC ->
|
|
|
|
// CCC, to avoid wrong ../../CCC -> CCC; relative paths
|
|
|
|
// shouldn't happen anyway, and even if they did, wouldn't
|
|
|
|
// match against WORKDIR anyway, as WORKDIR should be
|
|
|
|
// absolute):
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
s.erase(j, i + 3 - j); // AAA/BBB/..[/CCC] -> AAA[/CCC]
|
|
|
|
i = j;
|
|
|
|
} else {
|
|
|
|
i += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (strncmp(s.c_str(), WORKDIR, strlen(WORKDIR)) == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2014-01-10 11:07:55 +01:00
|
|
|
if( strncmp( bufferName, BUILDDIR, strlen( BUILDDIR )) == 0
|
2013-05-06 15:14:35 +02:00
|
|
|
|| strncmp( bufferName, SRCDIR, strlen( SRCDIR )) == 0 )
|
|
|
|
return false; // ok
|
|
|
|
return true;
|
2012-10-09 16:39:49 +02:00
|
|
|
}
|
|
|
|
|
2014-01-27 13:09:20 +01:00
|
|
|
void Plugin::registerPlugin( Plugin* (*create)( const InstantiationData& ), const char* optionName, bool isPPCallback, bool byDefault )
|
2013-02-02 17:45:18 +01:00
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
PluginHandler::registerPlugin( create, optionName, isPPCallback, byDefault );
|
2013-02-02 17:45:18 +01:00
|
|
|
}
|
|
|
|
|
2013-06-19 23:55:47 +02:00
|
|
|
unordered_map< const Stmt*, const Stmt* > Plugin::parents;
|
|
|
|
|
|
|
|
const Stmt* Plugin::parentStmt( const Stmt* stmt )
|
|
|
|
{
|
|
|
|
if( parents.empty())
|
|
|
|
buildParents( compiler );
|
2016-01-11 08:41:55 +02:00
|
|
|
//if(parents.count(stmt)!=1)stmt->dump();
|
|
|
|
//assert( parents.count( stmt ) == 1 );
|
2013-06-19 23:55:47 +02:00
|
|
|
return parents[ stmt ];
|
|
|
|
}
|
|
|
|
|
|
|
|
Stmt* Plugin::parentStmt( Stmt* stmt )
|
|
|
|
{
|
|
|
|
if( parents.empty())
|
|
|
|
buildParents( compiler );
|
2016-01-11 08:41:55 +02:00
|
|
|
//assert( parents.count( stmt ) == 1 );
|
2013-06-19 23:55:47 +02:00
|
|
|
return const_cast< Stmt* >( parents[ stmt ] );
|
|
|
|
}
|
|
|
|
|
2016-06-28 14:52:54 +02:00
|
|
|
static const Decl* getDeclContext(ASTContext& context, const Stmt* stmt)
|
|
|
|
{
|
|
|
|
auto it = context.getParents(*stmt).begin();
|
|
|
|
|
|
|
|
if (it == context.getParents(*stmt).end())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
const Decl *aDecl = it->get<Decl>();
|
|
|
|
if (aDecl)
|
|
|
|
return aDecl;
|
|
|
|
|
|
|
|
const Stmt *aStmt = it->get<Stmt>();
|
|
|
|
if (aStmt)
|
|
|
|
return getDeclContext(context, aStmt);
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
const FunctionDecl* Plugin::parentFunctionDecl( const Stmt* stmt )
|
|
|
|
{
|
|
|
|
const Decl *decl = getDeclContext(compiler.getASTContext(), stmt);
|
|
|
|
if (decl)
|
|
|
|
return static_cast<const FunctionDecl*>(decl->getNonClosureContext());
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-06-24 12:47:28 +02:00
|
|
|
|
|
|
|
bool Plugin::isInUnoIncludeFile(SourceLocation spellingLocation) const {
|
|
|
|
StringRef name {
|
|
|
|
compiler.getSourceManager().getFilename(spellingLocation) };
|
2016-06-29 09:15:05 +02:00
|
|
|
return compiler.getSourceManager().isInMainFile(spellingLocation)
|
2014-06-24 12:47:28 +02:00
|
|
|
? (name == SRCDIR "/cppu/source/cppu/compat.cxx"
|
|
|
|
|| name == SRCDIR "/cppuhelper/source/compat.cxx"
|
|
|
|
|| name == SRCDIR "/sal/osl/all/compat.cxx")
|
|
|
|
: (name.startswith(SRCDIR "/include/com/")
|
|
|
|
|| name.startswith(SRCDIR "/include/cppu/")
|
|
|
|
|| name.startswith(SRCDIR "/include/cppuhelper/")
|
|
|
|
|| name.startswith(SRCDIR "/include/osl/")
|
|
|
|
|| name.startswith(SRCDIR "/include/rtl/")
|
|
|
|
|| name.startswith(SRCDIR "/include/sal/")
|
|
|
|
|| name.startswith(SRCDIR "/include/salhelper/")
|
|
|
|
|| name.startswith(SRCDIR "/include/systools/")
|
|
|
|
|| name.startswith(SRCDIR "/include/typelib/")
|
|
|
|
|| name.startswith(SRCDIR "/include/uno/")
|
2015-06-22 21:48:36 +02:00
|
|
|
|| name.startswith(WORKDIR "/"));
|
2014-06-24 12:47:28 +02:00
|
|
|
}
|
|
|
|
|
2013-06-19 23:55:47 +02:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
class ParentBuilder
|
|
|
|
: public RecursiveASTVisitor< ParentBuilder >
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
bool VisitFunctionDecl( const FunctionDecl* function );
|
2014-02-21 23:38:54 +01:00
|
|
|
bool VisitObjCMethodDecl( const ObjCMethodDecl* method );
|
2013-06-19 23:55:47 +02:00
|
|
|
void walk( const Stmt* stmt );
|
2016-02-19 10:52:20 +02:00
|
|
|
bool shouldVisitTemplateInstantiations () const { return true; }
|
2013-06-19 23:55:47 +02:00
|
|
|
unordered_map< const Stmt*, const Stmt* >* parents;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool ParentBuilder::VisitFunctionDecl( const FunctionDecl* function )
|
|
|
|
{
|
|
|
|
// if( ignoreLocation( declaration ))
|
|
|
|
// return true; ???
|
2013-07-15 19:55:41 +02:00
|
|
|
if( function->doesThisDeclarationHaveABody())
|
|
|
|
{
|
|
|
|
const Stmt* body = function->getBody();
|
|
|
|
(*parents)[ body ] = NULL; // no parent
|
|
|
|
walk( body );
|
|
|
|
}
|
|
|
|
if( const CXXConstructorDecl* ctor = dyn_cast< CXXConstructorDecl >( function ))
|
|
|
|
{
|
|
|
|
for( CXXConstructorDecl::init_const_iterator it = ctor->init_begin();
|
|
|
|
it != ctor->init_end();
|
|
|
|
++it )
|
|
|
|
{
|
|
|
|
const Expr* init_expression = (*it)->getInit();
|
|
|
|
(*parents)[ init_expression ] = NULL;
|
|
|
|
walk( init_expression );
|
|
|
|
}
|
|
|
|
}
|
2013-06-19 23:55:47 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-02-21 23:38:54 +01:00
|
|
|
bool ParentBuilder::VisitObjCMethodDecl( const ObjCMethodDecl* method )
|
|
|
|
{
|
|
|
|
// if( ignoreLocation( declaration ))
|
|
|
|
// return true; ???
|
|
|
|
if( method->hasBody())
|
|
|
|
{
|
|
|
|
const Stmt* body = method->getBody();
|
|
|
|
(*parents)[ body ] = NULL; // no parent
|
|
|
|
walk( body );
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-06-19 23:55:47 +02:00
|
|
|
void ParentBuilder::walk( const Stmt* stmt )
|
|
|
|
{
|
|
|
|
for( ConstStmtIterator it = stmt->child_begin();
|
|
|
|
it != stmt->child_end();
|
|
|
|
++it )
|
|
|
|
{
|
|
|
|
if( *it != NULL )
|
|
|
|
{
|
|
|
|
(*parents)[ *it ] = stmt;
|
|
|
|
walk( *it );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
void Plugin::buildParents( CompilerInstance& compiler )
|
|
|
|
{
|
|
|
|
assert( parents.empty());
|
|
|
|
ParentBuilder builder;
|
|
|
|
builder.parents = &parents;
|
|
|
|
builder.TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
|
|
|
|
}
|
|
|
|
|
2013-08-14 18:43:01 +02:00
|
|
|
SourceLocation Plugin::locationAfterToken( SourceLocation location )
|
|
|
|
{
|
|
|
|
return Lexer::getLocForEndOfToken( location, 0, compiler.getSourceManager(), compiler.getLangOpts());
|
|
|
|
}
|
|
|
|
|
2014-01-27 13:09:20 +01:00
|
|
|
RewritePlugin::RewritePlugin( const InstantiationData& data )
|
|
|
|
: Plugin( data )
|
|
|
|
, rewriter( data.rewriter )
|
2012-10-15 17:34:13 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RewritePlugin::insertText( SourceLocation Loc, StringRef Str, bool InsertAfter, bool indentNewLines )
|
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
assert( rewriter );
|
|
|
|
if( rewriter->InsertText( Loc, Str, InsertAfter, indentNewLines ))
|
2012-10-15 17:34:13 +02:00
|
|
|
return reportEditFailure( Loc );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RewritePlugin::insertTextAfter( SourceLocation Loc, StringRef Str )
|
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
assert( rewriter );
|
|
|
|
if( rewriter->InsertTextAfter( Loc, Str ))
|
2012-10-15 17:34:13 +02:00
|
|
|
return reportEditFailure( Loc );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RewritePlugin::insertTextAfterToken( SourceLocation Loc, StringRef Str )
|
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
assert( rewriter );
|
|
|
|
if( rewriter->InsertTextAfterToken( Loc, Str ))
|
2012-10-15 17:34:13 +02:00
|
|
|
return reportEditFailure( Loc );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RewritePlugin::insertTextBefore( SourceLocation Loc, StringRef Str )
|
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
assert( rewriter );
|
|
|
|
if( rewriter->InsertTextBefore( Loc, Str ))
|
2012-10-15 17:34:13 +02:00
|
|
|
return reportEditFailure( Loc );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RewritePlugin::removeText( SourceLocation Start, unsigned Length, RewriteOptions opts )
|
|
|
|
{
|
2013-08-14 16:39:11 +02:00
|
|
|
CharSourceRange range( SourceRange( Start, Start.getLocWithOffset( Length )), false );
|
|
|
|
return removeText( range, opts );
|
2012-10-15 17:34:13 +02:00
|
|
|
}
|
|
|
|
|
2012-12-20 23:08:52 +01:00
|
|
|
bool RewritePlugin::removeText( SourceRange range, RewriteOptions opts )
|
2013-08-14 16:39:11 +02:00
|
|
|
{
|
|
|
|
return removeText( CharSourceRange( range, true ), opts );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RewritePlugin::removeText( CharSourceRange range, RewriteOptions opts )
|
2012-10-15 17:34:13 +02:00
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
assert( rewriter );
|
|
|
|
if( rewriter->getRangeSize( range, opts ) == -1 )
|
2013-08-20 19:42:16 +02:00
|
|
|
return reportEditFailure( range.getBegin());
|
2014-02-20 19:47:01 +01:00
|
|
|
if( !handler.addRemoval( range.getBegin() ) )
|
|
|
|
{
|
2013-05-06 16:41:27 +02:00
|
|
|
report( DiagnosticsEngine::Warning, "double code removal, possible plugin error", range.getBegin());
|
2014-02-20 19:47:01 +01:00
|
|
|
return true;
|
|
|
|
}
|
2013-08-14 16:39:11 +02:00
|
|
|
if( opts.flags & RemoveWholeStatement || opts.flags & RemoveAllWhitespace )
|
2012-12-20 23:08:52 +01:00
|
|
|
{
|
2013-08-14 16:39:11 +02:00
|
|
|
if( !adjustRangeForOptions( &range, opts ))
|
2012-12-20 23:08:52 +01:00
|
|
|
return reportEditFailure( range.getBegin());
|
|
|
|
}
|
2014-01-27 13:09:20 +01:00
|
|
|
if( rewriter->RemoveText( range, opts ))
|
2012-10-15 17:34:13 +02:00
|
|
|
return reportEditFailure( range.getBegin());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-08-14 16:39:11 +02:00
|
|
|
bool RewritePlugin::adjustRangeForOptions( CharSourceRange* range, RewriteOptions opts )
|
2012-10-15 17:34:13 +02:00
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
assert( rewriter );
|
|
|
|
SourceManager& SM = rewriter->getSourceMgr();
|
2012-12-20 23:08:52 +01:00
|
|
|
SourceLocation fileStartLoc = SM.getLocForStartOfFile( SM.getFileID( range->getBegin()));
|
|
|
|
if( fileStartLoc.isInvalid())
|
|
|
|
return false;
|
2015-09-25 11:41:53 +01:00
|
|
|
bool isInvalid = false;
|
|
|
|
const char* fileBuf = SM.getCharacterData( fileStartLoc, &isInvalid );
|
|
|
|
if( isInvalid )
|
2012-12-20 23:08:52 +01:00
|
|
|
return false;
|
2015-09-25 11:41:53 +01:00
|
|
|
const char* startBuf = SM.getCharacterData( range->getBegin(), &isInvalid );
|
|
|
|
if( isInvalid )
|
2012-12-20 23:08:52 +01:00
|
|
|
return false;
|
2013-08-14 16:39:11 +02:00
|
|
|
SourceLocation locationEnd = range->getEnd();
|
|
|
|
if( range->isTokenRange())
|
2013-08-14 18:43:01 +02:00
|
|
|
locationEnd = locationAfterToken( locationEnd );
|
2015-09-25 11:41:53 +01:00
|
|
|
const char* endBuf = SM.getCharacterData( locationEnd, &isInvalid );
|
|
|
|
if( isInvalid )
|
2012-12-20 23:08:52 +01:00
|
|
|
return false;
|
2013-08-14 16:39:11 +02:00
|
|
|
const char* startPos = startBuf;
|
|
|
|
--startPos;
|
|
|
|
while( startPos >= fileBuf && ( *startPos == ' ' || *startPos == '\t' ))
|
|
|
|
--startPos;
|
|
|
|
if( startPos >= fileBuf && *startPos == '\n' )
|
|
|
|
startPos = startBuf - 1; // do not remove indentation whitespace (RemoveLineIfEmpty can do that)
|
|
|
|
const char* endPos = endBuf;
|
|
|
|
while( *endPos == ' ' || *endPos == '\t' )
|
|
|
|
++endPos;
|
|
|
|
if( opts.flags & RemoveWholeStatement )
|
|
|
|
{
|
|
|
|
if( *endPos == ';' )
|
|
|
|
++endPos;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*range = CharSourceRange( SourceRange( range->getBegin().getLocWithOffset( startPos - startBuf + 1 ),
|
|
|
|
locationEnd.getLocWithOffset( endPos - endBuf )), false );
|
2012-10-15 17:34:13 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RewritePlugin::replaceText( SourceLocation Start, unsigned OrigLength, StringRef NewStr )
|
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
assert( rewriter );
|
2014-02-20 19:47:01 +01:00
|
|
|
if( OrigLength != 0 && !handler.addRemoval( Start ) )
|
|
|
|
{
|
2013-05-06 16:41:27 +02:00
|
|
|
report( DiagnosticsEngine::Warning, "double code replacement, possible plugin error", Start );
|
2014-02-20 19:47:01 +01:00
|
|
|
return true;
|
|
|
|
}
|
2014-01-27 13:09:20 +01:00
|
|
|
if( rewriter->ReplaceText( Start, OrigLength, NewStr ))
|
2012-10-15 17:34:13 +02:00
|
|
|
return reportEditFailure( Start );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RewritePlugin::replaceText( SourceRange range, StringRef NewStr )
|
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
assert( rewriter );
|
|
|
|
if( rewriter->getRangeSize( range ) == -1 )
|
2013-08-20 19:42:16 +02:00
|
|
|
return reportEditFailure( range.getBegin());
|
2014-02-20 19:47:01 +01:00
|
|
|
if( !handler.addRemoval( range.getBegin() ) )
|
|
|
|
{
|
2013-05-06 16:41:27 +02:00
|
|
|
report( DiagnosticsEngine::Warning, "double code replacement, possible plugin error", range.getBegin());
|
2014-02-20 19:47:01 +01:00
|
|
|
return true;
|
|
|
|
}
|
2014-01-27 13:09:20 +01:00
|
|
|
if( rewriter->ReplaceText( range, NewStr ))
|
2012-10-15 17:34:13 +02:00
|
|
|
return reportEditFailure( range.getBegin());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RewritePlugin::replaceText( SourceRange range, SourceRange replacementRange )
|
|
|
|
{
|
2014-01-27 13:09:20 +01:00
|
|
|
assert( rewriter );
|
|
|
|
if( rewriter->getRangeSize( range ) == -1 )
|
2013-08-20 19:42:16 +02:00
|
|
|
return reportEditFailure( range.getBegin());
|
2014-02-20 19:47:01 +01:00
|
|
|
if( !handler.addRemoval( range.getBegin() ) )
|
|
|
|
{
|
2013-05-06 16:41:27 +02:00
|
|
|
report( DiagnosticsEngine::Warning, "double code replacement, possible plugin error", range.getBegin());
|
2014-02-20 19:47:01 +01:00
|
|
|
return true;
|
|
|
|
}
|
2014-01-27 13:09:20 +01:00
|
|
|
if( rewriter->ReplaceText( range, replacementRange ))
|
2012-10-15 17:34:13 +02:00
|
|
|
return reportEditFailure( range.getBegin());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RewritePlugin::reportEditFailure( SourceLocation loc )
|
|
|
|
{
|
2013-02-02 19:38:56 +01:00
|
|
|
report( DiagnosticsEngine::Warning, "cannot perform source modification (macro expansion involved?)", loc );
|
2012-10-15 17:34:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-10-05 18:17:13 +02:00
|
|
|
} // namespace
|
2013-09-21 14:42:35 +01:00
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|