nss: upgrade to release 3.73
[LibreOffice.git] / compilerplugins / clang / plugin.hxx
blob577e8998b187c8ece6e5a376e81391b38b85b8d4
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 #ifndef PLUGIN_H
13 #define PLUGIN_H
15 #include <clang/AST/ASTContext.h>
16 #include <clang/AST/RecursiveASTVisitor.h>
17 #include <clang/Basic/FileManager.h>
18 #include <clang/Basic/SourceManager.h>
19 #include <clang/Frontend/CompilerInstance.h>
20 #include <clang/Lex/Preprocessor.h>
21 #include <unordered_map>
22 #include <vector>
24 #include <clang/Rewrite/Core/Rewriter.h>
26 #include "compat.hxx"
27 #include "pluginhandler.hxx"
29 using namespace clang;
30 using namespace llvm;
32 namespace loplugin
35 struct InstantiationData
37 const char* name;
38 PluginHandler& handler;
39 CompilerInstance& compiler;
40 Rewriter* rewriter;
43 /**
44 Base class for plugins.
46 If you want to create a non-rewriter action, inherit from this class. Remember to also
47 use Plugin::Registration.
49 class Plugin
51 public:
52 explicit Plugin( const InstantiationData& data );
53 virtual ~Plugin() {}
54 // The main function of the plugin.
55 // Note that for shared plugins, its functionality must be split into preRun() and postRun(),
56 // see sharedvisitor/generator.cxx .
57 virtual void run() = 0;
58 // Should be called from run() before TraverseDecl().
59 // If returns false, run() should not do anything.
60 virtual bool preRun() { return true; }
61 virtual void postRun() {}
62 template< typename T > class Registration;
63 // Returns location right after the end of the token that starts at the given location.
64 SourceLocation locationAfterToken( SourceLocation location );
65 virtual bool setSharedPlugin( Plugin* /*plugin*/, const char* /*name*/ ) { return false; }
66 enum { isPPCallback = false };
67 enum { isSharedPlugin = false };
68 protected:
69 DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc = SourceLocation()) const;
70 bool ignoreLocation( SourceLocation loc ) const
71 { return handler.ignoreLocation(loc); }
72 bool ignoreLocation( const Decl* decl ) const;
73 bool ignoreLocation( const Stmt* stmt ) const;
74 bool ignoreLocation(TypeLoc tloc) const;
75 CompilerInstance& compiler;
76 PluginHandler& handler;
77 /**
78 Returns the parent of the given AST node. Clang's internal AST representation doesn't provide this information,
79 it can only provide children, but getting the parent is often useful for inspecting a part of the AST.
81 const Stmt* getParentStmt( const Stmt* stmt );
82 Stmt* getParentStmt( Stmt* stmt );
83 const FunctionDecl* getParentFunctionDecl( const Stmt* stmt );
85 /**
86 Get filename of the given location. Use this instead of SourceManager::getFilename(), as that one
87 does not handle source with expanded #inline directives (used by Icecream for remote compilation).
89 StringRef getFilenameOfLocation(SourceLocation spellingLocation) const;
90 /**
91 Checks if the location is inside a UNO file, more specifically, if it forms part of the URE stable interface,
92 which is not allowed to be changed.
94 bool isInUnoIncludeFile(SourceLocation spellingLocation) const;
95 bool isInUnoIncludeFile(const FunctionDecl*) const;
97 bool isDebugMode() const { return handler.isDebugMode(); }
99 static bool isUnitTestMode();
101 bool containsPreprocessingConditionalInclusion(SourceRange range);
103 enum class IdenticalDefaultArgumentsResult { No, Yes, Maybe };
104 IdenticalDefaultArgumentsResult checkIdenticalDefaultArguments(
105 Expr const * argument1, Expr const * argument2);
107 private:
108 static void registerPlugin( Plugin* (*create)( const InstantiationData& ), const char* optionName,
109 bool isPPCallback, bool isSharedPlugin, bool byDefault );
110 template< typename T > static Plugin* createHelper( const InstantiationData& data );
111 bool evaluate(const Expr* expr, APSInt& x);
113 enum { isRewriter = false };
114 const char* name;
117 template<typename Derived>
118 class FilteringPlugin : public RecursiveASTVisitor<Derived>, public Plugin
120 public:
121 explicit FilteringPlugin( const InstantiationData& data ) : Plugin(data) {}
123 bool TraverseNamespaceDecl(NamespaceDecl * decl) {
124 if (ignoreLocation(compat::getBeginLoc(decl)))
125 return true;
126 return RecursiveASTVisitor<Derived>::TraverseNamespaceDecl(decl);
131 Base class for rewriter plugins.
133 Remember to also use Plugin::Registration.
135 class RewritePlugin
136 : public Plugin
138 public:
139 explicit RewritePlugin( const InstantiationData& data );
140 protected:
141 enum RewriteOption
143 // This enum allows passing just 'RemoveLineIfEmpty' to functions below.
144 // If the resulting line would be completely empty, it'll be removed.
145 RemoveLineIfEmpty = 1 << 0,
146 // Use this to remove the declaration/statement as a whole, i.e. all whitespace before the statement
147 // and the trailing semicolon (is not part of the AST element range itself).
148 // The trailing semicolon must be present.
149 RemoveWholeStatement = 1 << 1,
150 // Removes also all whitespace preceding and following the expression (completely, so that
151 // the preceding and following tokens would be right next to each other, follow with insertText( " " )
152 // if this is not wanted). Despite the name, indentation whitespace is not removed.
153 RemoveAllWhitespace = 1 << 2
155 struct RewriteOptions
156 : public Rewriter::RewriteOptions
158 RewriteOptions() : flags( 0 ) {}
159 explicit RewriteOptions( RewriteOption option );
160 const int flags;
162 // syntactic sugar to be able to write 'RemoveLineIfEmpty | RemoveWholeStatement'
163 friend RewriteOption operator|( RewriteOption option1, RewriteOption option2 );
164 // These following insert/remove/replaceText functions map to functions
165 // in clang::Rewriter, with these differences:
166 // - they (more intuitively) return false on failure rather than true
167 // - they report a warning when the change cannot be done
168 // - There are more options for easier removal of surroundings of a statement/expression.
169 bool insertText( SourceLocation Loc, StringRef Str,
170 bool InsertAfter = true, bool indentNewLines = false );
171 bool insertTextAfter( SourceLocation Loc, StringRef Str );
172 bool insertTextAfterToken( SourceLocation Loc, StringRef Str );
173 bool insertTextBefore( SourceLocation Loc, StringRef Str );
174 bool removeText( SourceLocation Start, unsigned Length, RewriteOptions opts = RewriteOptions());
175 bool removeText( CharSourceRange range, RewriteOptions opts = RewriteOptions());
176 bool removeText( SourceRange range, RewriteOptions opts = RewriteOptions());
177 bool replaceText( SourceLocation Start, unsigned OrigLength, StringRef NewStr );
178 bool replaceText( SourceRange range, StringRef NewStr );
179 bool replaceText( SourceRange range, SourceRange replacementRange );
180 Rewriter* rewriter;
181 private:
182 template< typename T > friend class Plugin::Registration;
183 enum { isRewriter = true };
184 bool wouldRewriteWorkdir(SourceLocation loc);
185 bool reportEditFailure( SourceLocation loc );
186 bool adjustRangeForOptions( CharSourceRange* range, RewriteOptions options );
190 Plugin registration helper.
192 If you create a new helper class, create also an instance of this class to automatically register it.
193 The passed argument is name of the plugin, used for explicitly invoking rewriter plugins
194 (it is ignored for non-rewriter plugins).
196 @code
197 static Plugin::Registration< NameOfClass > X( "nameofclass" );
198 @endcode
200 template< typename T >
201 class Plugin::Registration
203 public:
204 Registration( const char* optionName, bool byDefault = !T::isRewriter );
207 class RegistrationCreate
209 public:
210 template< typename T, bool > static T* create( const InstantiationData& data );
213 inline
214 bool Plugin::ignoreLocation( const Decl* decl ) const
216 return ignoreLocation( decl->getLocation());
219 inline
220 bool Plugin::ignoreLocation( const Stmt* stmt ) const
222 // Invalid location can happen at least for ImplicitCastExpr of
223 // ImplicitParam 'self' in Objective C method declarations:
224 return compat::getBeginLoc(stmt).isValid() && ignoreLocation( compat::getBeginLoc(stmt));
227 inline bool Plugin::ignoreLocation(TypeLoc tloc) const
229 // Invalid locations appear to happen at least with Clang 5.0.2 (but no longer with at least
230 // recent Clang 10 trunk):
231 auto const loc = tloc.getBeginLoc();
232 return loc.isValid() && ignoreLocation(loc);
235 template< typename T >
236 Plugin* Plugin::createHelper( const InstantiationData& data )
238 return new T( data );
241 template< typename T >
242 inline
243 Plugin::Registration< T >::Registration( const char* optionName, bool byDefault )
245 registerPlugin( &T::template createHelper< T >, optionName, T::isPPCallback, T::isSharedPlugin, byDefault );
248 inline
249 RewritePlugin::RewriteOptions::RewriteOptions( RewriteOption option )
250 : flags( option )
252 // Note that 'flags' stores also RemoveLineIfEmpty, it must be kept in sync with the base class.
253 if( flags & RewritePlugin::RemoveLineIfEmpty )
254 RemoveLineIfEmpty = true;
257 inline
258 RewritePlugin::RewriteOption operator|( RewritePlugin::RewriteOption option1, RewritePlugin::RewriteOption option2 )
260 return static_cast< RewritePlugin::RewriteOption >( int( option1 ) | int( option2 ));
263 template<typename Derived>
264 class FilteringRewritePlugin : public RecursiveASTVisitor<Derived>, public RewritePlugin
266 public:
267 explicit FilteringRewritePlugin( const InstantiationData& data ) : RewritePlugin(data) {}
269 bool TraverseNamespaceDecl(NamespaceDecl * decl) {
270 if (ignoreLocation(compat::getBeginLoc(decl)))
271 return true;
272 return RecursiveASTVisitor<Derived>::TraverseNamespaceDecl(decl);
276 void normalizeDotDotInFilePath(std::string&);
278 // Same as pathname.startswith(prefix), except on Windows, where pathname and
279 // prefix may also contain backslashes:
280 bool hasPathnamePrefix(StringRef pathname, StringRef prefix);
282 // Same as pathname == other, except on Windows, where pathname and other may
283 // also contain backslashes:
284 bool isSamePathname(StringRef pathname, StringRef other);
286 // It appears that, given a function declaration, there is no way to determine
287 // the language linkage of the function's type, only of the function's name
288 // (via FunctionDecl::isExternC); however, in a case like
290 // extern "C" { static void f(); }
292 // the function's name does not have C language linkage while the function's
293 // type does (as clarified in C++11 [decl.link]); cf. <http://clang-developers.
294 // 42468.n3.nabble.com/Language-linkage-of-function-type-tt4037248.html>
295 // "Language linkage of function type":
296 bool hasCLanguageLinkageType(FunctionDecl const * decl);
298 // Count the number of times the base class is present in the subclass hierarchy
300 int derivedFromCount(clang::QualType subclassType, clang::QualType baseclassType);
301 int derivedFromCount(const CXXRecordDecl* subtypeRecord, const CXXRecordDecl* baseRecord);
303 // It looks like Clang wrongly implements DR 4
304 // (<http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#4>) and treats
305 // a variable declared in an 'extern "..." {...}'-style linkage-specification as
306 // if it contained the 'extern' specifier:
307 bool hasExternalLinkage(VarDecl const * decl);
309 bool isSmartPointerType(const Expr*);
311 const Decl* getFunctionDeclContext(ASTContext& context, const Stmt* stmt);
313 } // namespace
315 #endif // COMPILEPLUGIN_H
317 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */