2 * This file is part of the LibreOffice project.
6 * This file is distributed under the University of Illinois Open Source
7 * License. See LICENSE.TXT for details.
13 #include <clang/Basic/FileManager.h>
15 #include "pluginhandler.hxx"
18 Base classes for plugin actions.
23 Plugin::Plugin( CompilerInstance
& compiler
)
24 : compiler( compiler
)
28 DiagnosticBuilder
Plugin::report( DiagnosticsEngine::Level level
, StringRef message
, SourceLocation loc
)
30 return report( level
, message
, compiler
, loc
);
33 DiagnosticBuilder
Plugin::report( DiagnosticsEngine::Level level
, StringRef message
, CompilerInstance
& compiler
,
36 DiagnosticsEngine
& diag
= compiler
.getDiagnostics();
38 // Do some mappings (e.g. for -Werror) that clang does not do for custom messages for some reason.
39 if( level
== DiagnosticsEngine::Warning
&& diag
.getWarningsAsErrors())
40 level
= DiagnosticsEngine::Error
;
41 if( level
== DiagnosticsEngine::Error
&& diag
.getErrorsAsFatal())
42 level
= DiagnosticsEngine::Fatal
;
44 string fullMessage
= ( message
+ " [loplugin]" ).str();
46 return diag
.Report( loc
, diag
.getCustomDiagID( level
, fullMessage
));
48 return diag
.Report( diag
.getCustomDiagID( level
, fullMessage
));
51 bool Plugin::ignoreLocation( SourceLocation loc
)
53 SourceLocation expansionLoc
= compiler
.getSourceManager().getExpansionLoc( loc
);
54 if( compiler
.getSourceManager().isInSystemHeader( expansionLoc
))
56 const char* bufferName
= compiler
.getSourceManager().getPresumedLoc( expansionLoc
).getFilename();
57 if( bufferName
== NULL
)
59 if( strncmp( bufferName
, OUTDIR
, strlen( OUTDIR
)) == 0
60 || strncmp( bufferName
, WORKDIR
, strlen( WORKDIR
)) == 0
61 || strncmp( bufferName
, BUILDDIR
, strlen( BUILDDIR
)) == 0
62 || strncmp( bufferName
, SRCDIR
, strlen( SRCDIR
)) == 0 )
67 void Plugin::registerPlugin( Plugin
* (*create
)( CompilerInstance
&, Rewriter
& ), const char* optionName
, bool isRewriter
)
69 PluginHandler::registerPlugin( create
, optionName
, isRewriter
);
74 RewritePlugin::RewritePlugin( CompilerInstance
& compiler
, Rewriter
& rewriter
)
76 , rewriter( rewriter
)
80 bool RewritePlugin::insertText( SourceLocation Loc
, StringRef Str
, bool InsertAfter
, bool indentNewLines
)
82 if( rewriter
.InsertText( Loc
, Str
, InsertAfter
, indentNewLines
))
83 return reportEditFailure( Loc
);
87 bool RewritePlugin::insertTextAfter( SourceLocation Loc
, StringRef Str
)
89 if( rewriter
.InsertTextAfter( Loc
, Str
))
90 return reportEditFailure( Loc
);
94 bool RewritePlugin::insertTextAfterToken( SourceLocation Loc
, StringRef Str
)
96 if( rewriter
.InsertTextAfterToken( Loc
, Str
))
97 return reportEditFailure( Loc
);
101 bool RewritePlugin::insertTextBefore( SourceLocation Loc
, StringRef Str
)
103 if( rewriter
.InsertTextBefore( Loc
, Str
))
104 return reportEditFailure( Loc
);
108 // These two removeText() overloads should not be merged into one, as the SourceRange
109 // one uses a token range (which counts token length for some reason), so exact length
110 // given to this overload would not match afterwards.
111 bool RewritePlugin::removeText( SourceLocation Start
, unsigned Length
, RewriteOptions opts
)
113 if( removals
.find( Start
) != removals
.end())
114 report( DiagnosticsEngine::Warning
, "double code removal, possible plugin error", Start
);
115 removals
.insert( Start
);
116 if( opts
.RemoveWholeStatement
)
118 SourceRange
range( Start
, Start
.getLocWithOffset( Length
- 1 ));
119 if( !adjustForWholeStatement( &range
))
120 return reportEditFailure( Start
);
121 Start
= range
.getBegin();
122 Length
= range
.getEnd().getRawEncoding() - range
.getBegin().getRawEncoding();
124 if( rewriter
.RemoveText( Start
, Length
, opts
))
125 return reportEditFailure( Start
);
129 bool RewritePlugin::removeText( SourceRange range
, RewriteOptions opts
)
131 if( removals
.find( range
.getBegin()) != removals
.end())
132 report( DiagnosticsEngine::Warning
, "double code removal, possible plugin error", range
.getBegin());
133 removals
.insert( range
.getBegin());
134 if( opts
.RemoveWholeStatement
)
136 if( !adjustForWholeStatement( &range
))
137 return reportEditFailure( range
.getBegin());
139 if( rewriter
.RemoveText( range
, opts
))
140 return reportEditFailure( range
.getBegin());
144 bool RewritePlugin::adjustForWholeStatement( SourceRange
* range
)
146 SourceManager
& SM
= rewriter
.getSourceMgr();
147 SourceLocation fileStartLoc
= SM
.getLocForStartOfFile( SM
.getFileID( range
->getBegin()));
148 if( fileStartLoc
.isInvalid())
150 bool invalid
= false;
151 const char* fileBuf
= SM
.getCharacterData( fileStartLoc
, &invalid
);
154 const char* startBuf
= SM
.getCharacterData( range
->getBegin(), &invalid
);
157 const char* endBuf
= SM
.getCharacterData( range
->getEnd(), &invalid
);
160 const char* startSpacePos
= startBuf
;
161 // do not skip \n here, RemoveLineIfEmpty can take care of that
163 while( startSpacePos
>= fileBuf
&& ( *startSpacePos
== ' ' || *startSpacePos
== '\t' ))
165 const char* semiPos
= strchr( endBuf
, ';' );
166 if( semiPos
== NULL
)
168 *range
= SourceRange( range
->getBegin().getLocWithOffset( startSpacePos
- startBuf
+ 1 ),
169 range
->getEnd().getLocWithOffset( semiPos
- endBuf
+ 1 ));
173 bool RewritePlugin::replaceText( SourceLocation Start
, unsigned OrigLength
, StringRef NewStr
)
175 if( OrigLength
!= 0 && removals
.find( Start
) != removals
.end())
176 report( DiagnosticsEngine::Warning
, "double code replacement, possible plugin error", Start
);
177 removals
.insert( Start
);
178 if( rewriter
.ReplaceText( Start
, OrigLength
, NewStr
))
179 return reportEditFailure( Start
);
183 bool RewritePlugin::replaceText( SourceRange range
, StringRef NewStr
)
185 if( removals
.find( range
.getBegin()) != removals
.end())
186 report( DiagnosticsEngine::Warning
, "double code replacement, possible plugin error", range
.getBegin());
187 removals
.insert( range
.getBegin());
188 if( rewriter
.ReplaceText( range
, NewStr
))
189 return reportEditFailure( range
.getBegin());
193 bool RewritePlugin::replaceText( SourceRange range
, SourceRange replacementRange
)
195 if( removals
.find( range
.getBegin()) != removals
.end())
196 report( DiagnosticsEngine::Warning
, "double code replacement, possible plugin error", range
.getBegin());
197 removals
.insert( range
.getBegin());
198 if( rewriter
.ReplaceText( range
, replacementRange
))
199 return reportEditFailure( range
.getBegin());
203 bool RewritePlugin::reportEditFailure( SourceLocation loc
)
205 report( DiagnosticsEngine::Warning
, "cannot perform source modification (macro expansion involved?)", loc
);