fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / compilerplugins / clang / plugin.cxx
blob4df8bac23d7826916c6f74c03603ef707b3dcea7
1 /*
2 * This file is part of the LibreOffice project.
4 * Based on LLVM/Clang.
6 * This file is distributed under the University of Illinois Open Source
7 * License. See LICENSE.TXT for details.
9 */
11 #include "plugin.hxx"
13 #include <clang/Basic/FileManager.h>
15 #include "pluginhandler.hxx"
18 Base classes for plugin actions.
20 namespace loplugin
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,
34 SourceLocation loc )
36 DiagnosticsEngine& diag = compiler.getDiagnostics();
37 #if 0
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;
43 #endif
44 string fullMessage = ( message + " [loplugin]" ).str();
45 if( loc.isValid())
46 return diag.Report( loc, diag.getCustomDiagID( level, fullMessage ));
47 else
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 ))
55 return true;
56 const char* bufferName = compiler.getSourceManager().getPresumedLoc( expansionLoc ).getFilename();
57 if( bufferName == NULL )
58 return true;
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 )
63 return false; // ok
64 return true;
67 void Plugin::registerPlugin( Plugin* (*create)( CompilerInstance&, Rewriter& ), const char* optionName, bool isRewriter )
69 PluginHandler::registerPlugin( create, optionName, isRewriter );
72 /////
74 RewritePlugin::RewritePlugin( CompilerInstance& compiler, Rewriter& rewriter )
75 : Plugin( compiler )
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 );
84 return true;
87 bool RewritePlugin::insertTextAfter( SourceLocation Loc, StringRef Str )
89 if( rewriter.InsertTextAfter( Loc, Str ))
90 return reportEditFailure( Loc );
91 return true;
94 bool RewritePlugin::insertTextAfterToken( SourceLocation Loc, StringRef Str )
96 if( rewriter.InsertTextAfterToken( Loc, Str ))
97 return reportEditFailure( Loc );
98 return true;
101 bool RewritePlugin::insertTextBefore( SourceLocation Loc, StringRef Str )
103 if( rewriter.InsertTextBefore( Loc, Str ))
104 return reportEditFailure( Loc );
105 return true;
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 );
126 return true;
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());
141 return true;
144 bool RewritePlugin::adjustForWholeStatement( SourceRange* range )
146 SourceManager& SM = rewriter.getSourceMgr();
147 SourceLocation fileStartLoc = SM.getLocForStartOfFile( SM.getFileID( range->getBegin()));
148 if( fileStartLoc.isInvalid())
149 return false;
150 bool invalid = false;
151 const char* fileBuf = SM.getCharacterData( fileStartLoc, &invalid );
152 if( invalid )
153 return false;
154 const char* startBuf = SM.getCharacterData( range->getBegin(), &invalid );
155 if( invalid )
156 return false;
157 const char* endBuf = SM.getCharacterData( range->getEnd(), &invalid );
158 if( invalid )
159 return false;
160 const char* startSpacePos = startBuf;
161 // do not skip \n here, RemoveLineIfEmpty can take care of that
162 --startSpacePos;
163 while( startSpacePos >= fileBuf && ( *startSpacePos == ' ' || *startSpacePos == '\t' ))
164 --startSpacePos;
165 const char* semiPos = strchr( endBuf, ';' );
166 if( semiPos == NULL )
167 return false;
168 *range = SourceRange( range->getBegin().getLocWithOffset( startSpacePos - startBuf + 1 ),
169 range->getEnd().getLocWithOffset( semiPos - endBuf + 1 ));
170 return true;
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 );
180 return true;
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());
190 return true;
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());
200 return true;
203 bool RewritePlugin::reportEditFailure( SourceLocation loc )
205 report( DiagnosticsEngine::Warning, "cannot perform source modification (macro expansion involved?)", loc );
206 return false;
209 } // namespace