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.
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>
24 #include <clang/Rewrite/Core/Rewriter.h>
27 #include "pluginhandler.hxx"
29 using namespace clang
;
35 struct InstantiationData
38 PluginHandler
& handler
;
39 CompilerInstance
& compiler
;
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.
52 explicit Plugin( const InstantiationData
& data
);
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 };
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 CompilerInstance
& compiler
;
75 PluginHandler
& handler
;
77 Returns the parent of the given AST node. Clang's internal AST representation doesn't provide this information,
78 it can only provide children, but getting the parent is often useful for inspecting a part of the AST.
80 const Stmt
* getParentStmt( const Stmt
* stmt
);
81 Stmt
* getParentStmt( Stmt
* stmt
);
82 const FunctionDecl
* getParentFunctionDecl( const Stmt
* stmt
);
84 /// to check file names against whitelists, so that it works with preprocessed input too
85 StringRef
getFileNameOfSpellingLoc(SourceLocation spellingLocation
) const;
87 Checks if the location is inside a UNO file, more specifically, if it forms part of the URE stable interface,
88 which is not allowed to be changed.
90 bool isInUnoIncludeFile(SourceLocation spellingLocation
) const;
91 bool isInUnoIncludeFile(const FunctionDecl
*) const;
93 bool isDebugMode() const { return handler
.isDebugMode(); }
95 static bool isUnitTestMode();
97 bool containsPreprocessingConditionalInclusion(SourceRange range
);
99 enum class IdenticalDefaultArgumentsResult
{ No
, Yes
, Maybe
};
100 IdenticalDefaultArgumentsResult
checkIdenticalDefaultArguments(
101 Expr
const * argument1
, Expr
const * argument2
);
104 static void registerPlugin( Plugin
* (*create
)( const InstantiationData
& ), const char* optionName
,
105 bool isPPCallback
, bool isSharedPlugin
, bool byDefault
);
106 template< typename T
> static Plugin
* createHelper( const InstantiationData
& data
);
107 bool evaluate(const Expr
* expr
, APSInt
& x
);
109 enum { isRewriter
= false };
113 template<typename Derived
>
114 class FilteringPlugin
: public RecursiveASTVisitor
<Derived
>, public Plugin
117 explicit FilteringPlugin( const InstantiationData
& data
) : Plugin(data
) {}
119 bool TraverseNamespaceDecl(NamespaceDecl
* decl
) {
120 if (ignoreLocation(compat::getBeginLoc(decl
)))
122 return RecursiveASTVisitor
<Derived
>::TraverseNamespaceDecl(decl
);
127 Base class for rewriter plugins.
129 Remember to also use Plugin::Registration.
135 explicit RewritePlugin( const InstantiationData
& data
);
139 // This enum allows passing just 'RemoveLineIfEmpty' to functions below.
140 // If the resulting line would be completely empty, it'll be removed.
141 RemoveLineIfEmpty
= 1 << 0,
142 // Use this to remove the declaration/statement as a whole, i.e. all whitespace before the statement
143 // and the trailing semicolon (is not part of the AST element range itself).
144 // The trailing semicolon must be present.
145 RemoveWholeStatement
= 1 << 1,
146 // Removes also all whitespace preceding and following the expression (completely, so that
147 // the preceding and following tokens would be right next to each other, follow with insertText( " " )
148 // if this is not wanted). Despite the name, indentation whitespace is not removed.
149 RemoveAllWhitespace
= 1 << 2
151 struct RewriteOptions
152 : public Rewriter::RewriteOptions
154 RewriteOptions() : flags( 0 ) {}
155 explicit RewriteOptions( RewriteOption option
);
158 // syntactic sugar to be able to write 'RemoveLineIfEmpty | RemoveWholeStatement'
159 friend RewriteOption
operator|( RewriteOption option1
, RewriteOption option2
);
160 // These following insert/remove/replaceText functions map to functions
161 // in clang::Rewriter, with these differences:
162 // - they (more intuitively) return false on failure rather than true
163 // - they report a warning when the change cannot be done
164 // - There are more options for easier removal of surroundings of a statement/expression.
165 bool insertText( SourceLocation Loc
, StringRef Str
,
166 bool InsertAfter
= true, bool indentNewLines
= false );
167 bool insertTextAfter( SourceLocation Loc
, StringRef Str
);
168 bool insertTextAfterToken( SourceLocation Loc
, StringRef Str
);
169 bool insertTextBefore( SourceLocation Loc
, StringRef Str
);
170 bool removeText( SourceLocation Start
, unsigned Length
, RewriteOptions opts
= RewriteOptions());
171 bool removeText( CharSourceRange range
, RewriteOptions opts
= RewriteOptions());
172 bool removeText( SourceRange range
, RewriteOptions opts
= RewriteOptions());
173 bool replaceText( SourceLocation Start
, unsigned OrigLength
, StringRef NewStr
);
174 bool replaceText( SourceRange range
, StringRef NewStr
);
175 bool replaceText( SourceRange range
, SourceRange replacementRange
);
178 template< typename T
> friend class Plugin::Registration
;
179 enum { isRewriter
= true };
180 bool wouldRewriteWorkdir(SourceLocation loc
);
181 bool reportEditFailure( SourceLocation loc
);
182 bool adjustRangeForOptions( CharSourceRange
* range
, RewriteOptions options
);
186 Plugin registration helper.
188 If you create a new helper class, create also an instance of this class to automatically register it.
189 The passed argument is name of the plugin, used for explicitly invoking rewriter plugins
190 (it is ignored for non-rewriter plugins).
193 static Plugin::Registration< NameOfClass > X( "nameofclass" );
196 template< typename T
>
197 class Plugin::Registration
200 Registration( const char* optionName
, bool byDefault
= !T::isRewriter
);
203 class RegistrationCreate
206 template< typename T
, bool > static T
* create( const InstantiationData
& data
);
210 bool Plugin::ignoreLocation( const Decl
* decl
) const
212 return ignoreLocation( decl
->getLocation());
216 bool Plugin::ignoreLocation( const Stmt
* stmt
) const
218 // Invalid location can happen at least for ImplicitCastExpr of
219 // ImplicitParam 'self' in Objective C method declarations:
220 return compat::getBeginLoc(stmt
).isValid() && ignoreLocation( compat::getBeginLoc(stmt
));
223 template< typename T
>
224 Plugin
* Plugin::createHelper( const InstantiationData
& data
)
226 return new T( data
);
229 template< typename T
>
231 Plugin::Registration
< T
>::Registration( const char* optionName
, bool byDefault
)
233 registerPlugin( &T::template createHelper
< T
>, optionName
, T::isPPCallback
, T::isSharedPlugin
, byDefault
);
237 RewritePlugin::RewriteOptions::RewriteOptions( RewriteOption option
)
240 // Note that 'flags' stores also RemoveLineIfEmpty, it must be kept in sync with the base class.
241 if( flags
& RewritePlugin::RemoveLineIfEmpty
)
242 RemoveLineIfEmpty
= true;
246 RewritePlugin::RewriteOption
operator|( RewritePlugin::RewriteOption option1
, RewritePlugin::RewriteOption option2
)
248 return static_cast< RewritePlugin::RewriteOption
>( int( option1
) | int( option2
));
251 template<typename Derived
>
252 class FilteringRewritePlugin
: public RecursiveASTVisitor
<Derived
>, public RewritePlugin
255 explicit FilteringRewritePlugin( const InstantiationData
& data
) : RewritePlugin(data
) {}
257 bool TraverseNamespaceDecl(NamespaceDecl
* decl
) {
258 if (ignoreLocation(compat::getBeginLoc(decl
)))
260 return RecursiveASTVisitor
<Derived
>::TraverseNamespaceDecl(decl
);
264 void normalizeDotDotInFilePath(std::string
&);
266 // Same as pathname.startswith(prefix), except on Windows, where pathname and
267 // prefix may also contain backslashes:
268 bool hasPathnamePrefix(StringRef pathname
, StringRef prefix
);
270 // Same as pathname == other, except on Windows, where pathname and other may
271 // also contain backslashes:
272 bool isSamePathname(StringRef pathname
, StringRef other
);
276 #endif // COMPILEPLUGIN_H
278 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */