1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
16 #include <clang/Basic/FileManager.h>
17 #include <clang/Lex/Lexer.h>
19 #include "pluginhandler.hxx"
23 Base classes for plugin actions.
28 Plugin::Plugin( const InstantiationData
& data
)
29 : compiler( data
.compiler
), handler( data
.handler
), name( data
.name
)
33 DiagnosticBuilder
Plugin::report( DiagnosticsEngine::Level level
, StringRef message
, SourceLocation loc
) const
35 return handler
.report( level
, name
, message
, compiler
, loc
);
38 bool Plugin::ignoreLocation( SourceLocation loc
)
40 SourceLocation expansionLoc
= compiler
.getSourceManager().getExpansionLoc( loc
);
41 if( compiler
.getSourceManager().isInSystemHeader( expansionLoc
))
43 const char* bufferName
= compiler
.getSourceManager().getPresumedLoc( expansionLoc
).getFilename();
44 if( bufferName
== NULL
45 || strncmp( bufferName
, WORKDIR
, strlen( WORKDIR
)) == 0 )
47 if( strncmp( bufferName
, BUILDDIR
, strlen( BUILDDIR
)) == 0
48 || strncmp( bufferName
, SRCDIR
, strlen( SRCDIR
)) == 0 )
53 void Plugin::registerPlugin( Plugin
* (*create
)( const InstantiationData
& ), const char* optionName
, bool isPPCallback
, bool byDefault
)
55 PluginHandler::registerPlugin( create
, optionName
, isPPCallback
, byDefault
);
58 unordered_map
< const Stmt
*, const Stmt
* > Plugin::parents
;
60 const Stmt
* Plugin::parentStmt( const Stmt
* stmt
)
63 buildParents( compiler
);
64 if(parents
.count(stmt
)!=1)stmt
->dump();
65 assert( parents
.count( stmt
) == 1 );
66 return parents
[ stmt
];
69 Stmt
* Plugin::parentStmt( Stmt
* stmt
)
72 buildParents( compiler
);
73 assert( parents
.count( stmt
) == 1 );
74 return const_cast< Stmt
* >( parents
[ stmt
] );
78 bool Plugin::isInUnoIncludeFile(SourceLocation spellingLocation
) const {
80 compiler
.getSourceManager().getFilename(spellingLocation
) };
81 return compat::isInMainFile(compiler
.getSourceManager(), spellingLocation
)
82 ? (name
== SRCDIR
"/cppu/source/cppu/compat.cxx"
83 || name
== SRCDIR
"/cppuhelper/source/compat.cxx"
84 || name
== SRCDIR
"/sal/osl/all/compat.cxx")
85 : (name
.startswith(SRCDIR
"/include/com/")
86 || name
.startswith(SRCDIR
"/include/cppu/")
87 || name
.startswith(SRCDIR
"/include/cppuhelper/")
88 || name
.startswith(SRCDIR
"/include/osl/")
89 || name
.startswith(SRCDIR
"/include/rtl/")
90 || name
.startswith(SRCDIR
"/include/sal/")
91 || name
.startswith(SRCDIR
"/include/salhelper/")
92 || name
.startswith(SRCDIR
"/include/systools/")
93 || name
.startswith(SRCDIR
"/include/typelib/")
94 || name
.startswith(SRCDIR
"/include/uno/")
95 || name
.startswith(SRCDIR
"/workdir/")
96 || name
== SRCDIR
"/include/comphelper/implbase_var.hxx");
102 : public RecursiveASTVisitor
< ParentBuilder
>
105 bool VisitFunctionDecl( const FunctionDecl
* function
);
106 bool VisitObjCMethodDecl( const ObjCMethodDecl
* method
);
107 void walk( const Stmt
* stmt
);
108 unordered_map
< const Stmt
*, const Stmt
* >* parents
;
111 bool ParentBuilder::VisitFunctionDecl( const FunctionDecl
* function
)
113 // if( ignoreLocation( declaration ))
115 if( function
->doesThisDeclarationHaveABody())
117 const Stmt
* body
= function
->getBody();
118 (*parents
)[ body
] = NULL
; // no parent
121 if( const CXXConstructorDecl
* ctor
= dyn_cast
< CXXConstructorDecl
>( function
))
123 for( CXXConstructorDecl::init_const_iterator it
= ctor
->init_begin();
124 it
!= ctor
->init_end();
127 const Expr
* init_expression
= (*it
)->getInit();
128 (*parents
)[ init_expression
] = NULL
;
129 walk( init_expression
);
135 bool ParentBuilder::VisitObjCMethodDecl( const ObjCMethodDecl
* method
)
137 // if( ignoreLocation( declaration ))
139 if( method
->hasBody())
141 const Stmt
* body
= method
->getBody();
142 (*parents
)[ body
] = NULL
; // no parent
148 void ParentBuilder::walk( const Stmt
* stmt
)
150 for( ConstStmtIterator it
= stmt
->child_begin();
151 it
!= stmt
->child_end();
156 (*parents
)[ *it
] = stmt
;
164 void Plugin::buildParents( CompilerInstance
& compiler
)
166 assert( parents
.empty());
167 ParentBuilder builder
;
168 builder
.parents
= &parents
;
169 builder
.TraverseDecl( compiler
.getASTContext().getTranslationUnitDecl());
172 SourceLocation
Plugin::locationAfterToken( SourceLocation location
)
174 return Lexer::getLocForEndOfToken( location
, 0, compiler
.getSourceManager(), compiler
.getLangOpts());
177 RewritePlugin::RewritePlugin( const InstantiationData
& data
)
179 , rewriter( data
.rewriter
)
183 bool RewritePlugin::insertText( SourceLocation Loc
, StringRef Str
, bool InsertAfter
, bool indentNewLines
)
186 if( rewriter
->InsertText( Loc
, Str
, InsertAfter
, indentNewLines
))
187 return reportEditFailure( Loc
);
191 bool RewritePlugin::insertTextAfter( SourceLocation Loc
, StringRef Str
)
194 if( rewriter
->InsertTextAfter( Loc
, Str
))
195 return reportEditFailure( Loc
);
199 bool RewritePlugin::insertTextAfterToken( SourceLocation Loc
, StringRef Str
)
202 if( rewriter
->InsertTextAfterToken( Loc
, Str
))
203 return reportEditFailure( Loc
);
207 bool RewritePlugin::insertTextBefore( SourceLocation Loc
, StringRef Str
)
210 if( rewriter
->InsertTextBefore( Loc
, Str
))
211 return reportEditFailure( Loc
);
215 bool RewritePlugin::removeText( SourceLocation Start
, unsigned Length
, RewriteOptions opts
)
217 CharSourceRange
range( SourceRange( Start
, Start
.getLocWithOffset( Length
)), false );
218 return removeText( range
, opts
);
221 bool RewritePlugin::removeText( SourceRange range
, RewriteOptions opts
)
223 return removeText( CharSourceRange( range
, true ), opts
);
226 bool RewritePlugin::removeText( CharSourceRange range
, RewriteOptions opts
)
229 if( rewriter
->getRangeSize( range
, opts
) == -1 )
230 return reportEditFailure( range
.getBegin());
231 if( !handler
.addRemoval( range
.getBegin() ) )
233 report( DiagnosticsEngine::Warning
, "double code removal, possible plugin error", range
.getBegin());
236 if( opts
.flags
& RemoveWholeStatement
|| opts
.flags
& RemoveAllWhitespace
)
238 if( !adjustRangeForOptions( &range
, opts
))
239 return reportEditFailure( range
.getBegin());
241 if( rewriter
->RemoveText( range
, opts
))
242 return reportEditFailure( range
.getBegin());
246 bool RewritePlugin::adjustRangeForOptions( CharSourceRange
* range
, RewriteOptions opts
)
249 SourceManager
& SM
= rewriter
->getSourceMgr();
250 SourceLocation fileStartLoc
= SM
.getLocForStartOfFile( SM
.getFileID( range
->getBegin()));
251 if( fileStartLoc
.isInvalid())
253 bool invalid
= false;
254 const char* fileBuf
= SM
.getCharacterData( fileStartLoc
, &invalid
);
257 const char* startBuf
= SM
.getCharacterData( range
->getBegin(), &invalid
);
260 SourceLocation locationEnd
= range
->getEnd();
261 if( range
->isTokenRange())
262 locationEnd
= locationAfterToken( locationEnd
);
263 const char* endBuf
= SM
.getCharacterData( locationEnd
, &invalid
);
266 const char* startPos
= startBuf
;
268 while( startPos
>= fileBuf
&& ( *startPos
== ' ' || *startPos
== '\t' ))
270 if( startPos
>= fileBuf
&& *startPos
== '\n' )
271 startPos
= startBuf
- 1; // do not remove indentation whitespace (RemoveLineIfEmpty can do that)
272 const char* endPos
= endBuf
;
273 while( *endPos
== ' ' || *endPos
== '\t' )
275 if( opts
.flags
& RemoveWholeStatement
)
282 *range
= CharSourceRange( SourceRange( range
->getBegin().getLocWithOffset( startPos
- startBuf
+ 1 ),
283 locationEnd
.getLocWithOffset( endPos
- endBuf
)), false );
287 bool RewritePlugin::replaceText( SourceLocation Start
, unsigned OrigLength
, StringRef NewStr
)
290 if( OrigLength
!= 0 && !handler
.addRemoval( Start
) )
292 report( DiagnosticsEngine::Warning
, "double code replacement, possible plugin error", Start
);
295 if( rewriter
->ReplaceText( Start
, OrigLength
, NewStr
))
296 return reportEditFailure( Start
);
300 bool RewritePlugin::replaceText( SourceRange range
, StringRef NewStr
)
303 if( rewriter
->getRangeSize( range
) == -1 )
304 return reportEditFailure( range
.getBegin());
305 if( !handler
.addRemoval( range
.getBegin() ) )
307 report( DiagnosticsEngine::Warning
, "double code replacement, possible plugin error", range
.getBegin());
310 if( rewriter
->ReplaceText( range
, NewStr
))
311 return reportEditFailure( range
.getBegin());
315 bool RewritePlugin::replaceText( SourceRange range
, SourceRange replacementRange
)
318 if( rewriter
->getRangeSize( range
) == -1 )
319 return reportEditFailure( range
.getBegin());
320 if( !handler
.addRemoval( range
.getBegin() ) )
322 report( DiagnosticsEngine::Warning
, "double code replacement, possible plugin error", range
.getBegin());
325 if( rewriter
->ReplaceText( range
, replacementRange
))
326 return reportEditFailure( range
.getBegin());
330 bool RewritePlugin::reportEditFailure( SourceLocation loc
)
332 report( DiagnosticsEngine::Warning
, "cannot perform source modification (macro expansion involved?)", loc
);
338 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */