GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / compilerplugins / clang / pluginhandler.cxx
bloba49398a53a820335deb1dc0efdc185fa8102356d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * Based on LLVM/Clang.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
12 #include "pluginhandler.hxx"
14 #include <clang/Frontend/CompilerInstance.h>
15 #include <clang/Frontend/FrontendPluginRegistry.h>
16 #include <clang/Lex/PPCallbacks.h>
17 #include <stdio.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
22 This source file manages all plugin actions. It is not necessary to modify this
23 file when adding new actions.
26 namespace
29 bool isPrefix( const string& prefix, const string& full)
31 return full.compare(0, prefix.size(), prefix) == 0;
36 namespace loplugin
39 struct PluginData
41 Plugin* (*create)( CompilerInstance&, Rewriter& );
42 Plugin* object;
43 const char* optionName;
44 bool isRewriter;
45 bool isPPCallback;
48 const int MAX_PLUGINS = 100;
49 static PluginData plugins[ MAX_PLUGINS ];
50 static int pluginCount = 0;
51 static bool pluginObjectsCreated = false;
53 PluginHandler::PluginHandler( CompilerInstance& compiler, const vector< string >& args )
54 : compiler( compiler )
55 , rewriter( compiler.getSourceManager(), compiler.getLangOpts())
56 , scope( "mainfile" )
58 bool wasPlugin = false;
59 for( vector< string >::const_iterator it = args.begin();
60 it != args.end();
61 ++it )
63 if( it->size() >= 2 && (*it)[ 0 ] == '-' && (*it)[ 1 ] == '-' )
64 handleOption( it->substr( 2 ));
65 else
67 createPlugin( *it );
68 wasPlugin = true;
71 if( !wasPlugin )
72 createPlugin( "" ); // = all non-rewriters
73 pluginObjectsCreated = true;
76 PluginHandler::~PluginHandler()
78 for( int i = 0;
79 i < pluginCount;
80 ++i )
81 if( plugins[ i ].object != NULL )
83 // PPCallbacks is owned by preprocessor object, don't delete those
84 if( !plugins[ i ].isPPCallback )
85 delete plugins[ i ].object;
89 void PluginHandler::handleOption( const string& option )
91 if( option.substr( 0, 6 ) == "scope=" )
93 scope = option.substr( 6 );
94 if( scope == "mainfile" || scope == "all" )
95 ; // ok
96 else
98 struct stat st;
99 if( stat(( SRCDIR "/" + scope ).c_str(), &st ) != 0 || !S_ISDIR( st.st_mode ))
100 report( DiagnosticsEngine::Fatal, "unknown scope %0 (no such module directory)" ) << scope;
103 else
104 report( DiagnosticsEngine::Fatal, "unknown option %0" ) << option;
107 void PluginHandler::createPlugin( const string& name )
109 for( int i = 0;
110 i < pluginCount;
111 ++i )
113 if( name.empty()) // no plugin given -> create non-writer plugins
115 if( !plugins[ i ].isRewriter )
116 plugins[ i ].object = plugins[ i ].create( compiler, rewriter );
118 else if( plugins[ i ].optionName == name )
120 plugins[ i ].object = plugins[ i ].create( compiler, rewriter );
121 return;
124 if( !name.empty())
125 report( DiagnosticsEngine::Fatal, "unknown plugin tool %0" ) << name;
128 void PluginHandler::registerPlugin( Plugin* (*create)( CompilerInstance&, Rewriter& ), const char* optionName, bool isRewriter, bool isPPCallback )
130 assert( !pluginObjectsCreated );
131 assert( pluginCount < MAX_PLUGINS );
132 plugins[ pluginCount ].create = create;
133 plugins[ pluginCount ].object = NULL;
134 plugins[ pluginCount ].optionName = optionName;
135 plugins[ pluginCount ].isRewriter = isRewriter;
136 plugins[ pluginCount ].isPPCallback = isPPCallback;
137 ++pluginCount;
140 DiagnosticBuilder PluginHandler::report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc )
142 return Plugin::report( level, message, compiler, loc );
145 void PluginHandler::HandleTranslationUnit( ASTContext& context )
147 if( context.getDiagnostics().hasErrorOccurred())
148 return;
149 for( int i = 0;
150 i < pluginCount;
151 ++i )
153 if( plugins[ i ].object != NULL )
154 plugins[ i ].object->run();
156 for( Rewriter::buffer_iterator it = rewriter.buffer_begin();
157 it != rewriter.buffer_end();
158 ++it )
160 const FileEntry* e = context.getSourceManager().getFileEntryForID( it->first );
161 if( e == NULL )
162 continue; // Failed modification because of a macro expansion?
163 /* Check where the file actually is, and warn about cases where modification
164 most probably doesn't matter (generated files in workdir).
165 The order here is important, as INSTDIR and WORKDIR are often in SRCDIR/BUILDDIR,
166 and BUILDDIR is sometimes in SRCDIR. */
167 string modifyFile;
168 const char* pathWarning = NULL;
169 bool skip = false;
170 if( strncmp( e->getName(), WORKDIR "/", strlen( WORKDIR "/" )) == 0 )
171 pathWarning = "modified source in workdir/ : %0";
172 else if( strcmp( SRCDIR, BUILDDIR ) != 0 && strncmp( e->getName(), BUILDDIR "/", strlen( BUILDDIR "/" )) == 0 )
173 pathWarning = "modified source in build dir : %0";
174 else if( strncmp( e->getName(), SRCDIR "/", strlen( SRCDIR "/" )) == 0 )
175 ; // ok
176 else
178 pathWarning = "modified source in unknown location, not modifying : %0";
179 skip = true;
181 if( modifyFile.empty())
182 modifyFile = e->getName();
183 // Check whether the modified file is in the wanted scope
184 if( scope == "mainfile" )
186 if( it->first != context.getSourceManager().getMainFileID())
187 continue;
189 else if( scope == "all" )
190 ; // ok
191 else // scope is module
193 if( !( isPrefix( SRCDIR "/" + scope + "/", modifyFile ) || isPrefix( SRCDIR "/include/" + scope + "/", modifyFile ) ) )
194 continue;
196 // Warn only now, so that files not in scope do not cause warnings.
197 if( pathWarning != NULL )
198 report( DiagnosticsEngine::Warning, pathWarning ) << e->getName();
199 if( skip )
200 continue;
201 char* filename = new char[ modifyFile.length() + 100 ];
202 sprintf( filename, "%s.new.%d", modifyFile.c_str(), getpid());
203 string error;
204 bool ok = false;
205 raw_fd_ostream ostream( filename, error );
206 if( error.empty())
208 it->second.write( ostream );
209 ostream.close();
210 if( !ostream.has_error() && rename( filename, modifyFile.c_str()) == 0 )
211 ok = true;
213 ostream.clear_error();
214 unlink( filename );
215 if( !ok )
216 report( DiagnosticsEngine::Error, "cannot write modified source to %0 (%1)" ) << modifyFile << error;
217 delete[] filename;
221 ASTConsumer* LibreOfficeAction::CreateASTConsumer( CompilerInstance& Compiler, StringRef )
223 return new PluginHandler( Compiler, _args );
226 bool LibreOfficeAction::ParseArgs( const CompilerInstance&, const vector< string >& args )
228 _args = args;
229 return true;
233 static FrontendPluginRegistry::Add< loplugin::LibreOfficeAction > X( "loplugin", "LibreOffice compile check plugin" );
235 } // namespace
237 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */