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.
14 #include <clang/AST/ASTContext.h>
15 #include <clang/AST/RecursiveASTVisitor.h>
16 #include <clang/Basic/FileManager.h>
17 #include <clang/Basic/SourceManager.h>
18 #include <clang/Frontend/CompilerInstance.h>
19 #include <clang/Lex/Preprocessor.h>
20 #include <unordered_map>
23 #include <clang/Rewrite/Core/Rewriter.h>
25 #include "pluginhandler.hxx"
27 using namespace clang
;
33 struct InstantiationData
36 PluginHandler
& handler
;
37 CompilerInstance
& compiler
;
42 Base class for plugins.
44 If you want to create a non-rewriter action, inherit from this class. Remember to also
45 use Plugin::Registration.
50 explicit Plugin( const InstantiationData
& data
);
52 // The main function of the plugin.
53 // Note that for shared plugins, its functionality must be split into preRun() and postRun(),
54 // see sharedvisitor/generator.cxx .
55 virtual void run() = 0;
56 // Should be called from run() before TraverseDecl().
57 // If returns false, run() should not do anything.
58 virtual bool preRun() { return true; }
59 virtual void postRun() {}
60 template< typename T
> class Registration
;
61 // Returns location right after the end of the token that starts at the given location.
62 SourceLocation
locationAfterToken( SourceLocation location
);
63 virtual bool setSharedPlugin( Plugin
* /*plugin*/, const char* /*name*/ ) { return false; }
64 enum { isPPCallback
= false };
65 enum { isSharedPlugin
= false };
67 DiagnosticBuilder
report( DiagnosticsEngine::Level level
, StringRef message
, SourceLocation loc
= SourceLocation()) const;
68 // Look at the line containing location and the previous line for any comments that overlap
69 // either of those two lines and that contain "[-loplugin:<name>]" (with the name of this
70 // plugin), indicating that warnings from this plugin should be suppressed here:
71 bool suppressWarningAt(SourceLocation location
) const;
72 bool ignoreLocation( SourceLocation loc
) const
73 { return handler
.ignoreLocation(loc
); }
74 bool ignoreLocation( const Decl
* decl
) const;
75 bool ignoreLocation( const Stmt
* stmt
) const;
76 bool ignoreLocation(TypeLoc tloc
) const;
77 CompilerInstance
& compiler
;
78 PluginHandler
& handler
;
80 Returns the parent of the given AST node. Clang's internal AST representation doesn't provide this information,
81 it can only provide children, but getting the parent is often useful for inspecting a part of the AST.
83 const Stmt
* getParentStmt( const Stmt
* stmt
);
84 Stmt
* getParentStmt( Stmt
* stmt
);
85 const FunctionDecl
* getParentFunctionDecl( const Stmt
* stmt
);
88 Get filename of the given location. Use this instead of SourceManager::getFilename(), as that one
89 does not handle source with expanded #inline directives (used by Icecream for remote compilation).
91 StringRef
getFilenameOfLocation(SourceLocation spellingLocation
) const;
93 Checks if the location is inside a UNO file, more specifically, if it forms part of the URE stable interface,
94 which is not allowed to be changed.
96 bool isInUnoIncludeFile(SourceLocation spellingLocation
) const;
97 bool isInUnoIncludeFile(const FunctionDecl
*) const;
99 bool isDebugMode() const { return handler
.isDebugMode(); }
101 static bool isUnitTestMode();
103 bool containsPreprocessingConditionalInclusion(SourceRange range
);
105 bool containsComment(SourceRange range
);
107 enum class IdenticalDefaultArgumentsResult
{ No
, Yes
, Maybe
};
108 IdenticalDefaultArgumentsResult
checkIdenticalDefaultArguments(
109 Expr
const * argument1
, Expr
const * argument2
);
112 static void registerPlugin( Plugin
* (*create
)( const InstantiationData
& ), const char* optionName
,
113 bool isPPCallback
, bool isSharedPlugin
, bool byDefault
);
114 template< typename T
> static Plugin
* createHelper( const InstantiationData
& data
);
115 bool evaluate(const Expr
* expr
, APSInt
& x
);
117 enum { isRewriter
= false };
121 template<typename Derived
>
122 class FilteringPlugin
: public RecursiveASTVisitor
<Derived
>, public Plugin
125 explicit FilteringPlugin( const InstantiationData
& data
) : Plugin(data
) {}
127 bool TraverseNamespaceDecl(NamespaceDecl
* decl
) {
128 if (ignoreLocation(decl
->getBeginLoc()))
130 return RecursiveASTVisitor
<Derived
>::TraverseNamespaceDecl(decl
);
135 Base class for rewriter plugins.
137 Remember to also use Plugin::Registration.
143 explicit RewritePlugin( const InstantiationData
& data
);
147 // This enum allows passing just 'RemoveLineIfEmpty' to functions below.
148 // If the resulting line would be completely empty, it'll be removed.
149 RemoveLineIfEmpty
= 1 << 0,
150 // Use this to remove the declaration/statement as a whole, i.e. all whitespace before the statement
151 // and the trailing semicolon (is not part of the AST element range itself).
152 // The trailing semicolon must be present.
153 RemoveWholeStatement
= 1 << 1,
154 // Removes also all whitespace preceding and following the expression (completely, so that
155 // the preceding and following tokens would be right next to each other, follow with insertText( " " )
156 // if this is not wanted). Despite the name, indentation whitespace is not removed.
157 RemoveAllWhitespace
= 1 << 2
159 struct RewriteOptions
160 : public Rewriter::RewriteOptions
162 RewriteOptions() : flags( 0 ) {}
163 explicit RewriteOptions( RewriteOption option
);
166 // syntactic sugar to be able to write 'RemoveLineIfEmpty | RemoveWholeStatement'
167 friend RewriteOption
operator|( RewriteOption option1
, RewriteOption option2
);
168 // These following insert/remove/replaceText functions map to functions
169 // in clang::Rewriter, with these differences:
170 // - they (more intuitively) return false on failure rather than true
171 // - they report a warning when the change cannot be done
172 // - There are more options for easier removal of surroundings of a statement/expression.
173 bool insertText( SourceLocation Loc
, StringRef Str
,
174 bool InsertAfter
= true, bool indentNewLines
= false );
175 bool insertTextAfter( SourceLocation Loc
, StringRef Str
);
176 bool insertTextAfterToken( SourceLocation Loc
, StringRef Str
);
177 bool insertTextBefore( SourceLocation Loc
, StringRef Str
);
178 bool removeText( SourceLocation Start
, unsigned Length
, RewriteOptions opts
= RewriteOptions());
179 bool removeText( CharSourceRange range
, RewriteOptions opts
= RewriteOptions());
180 bool removeText( SourceRange range
, RewriteOptions opts
= RewriteOptions());
181 bool replaceText( SourceLocation Start
, unsigned OrigLength
, StringRef NewStr
);
182 bool replaceText( SourceRange range
, StringRef NewStr
);
183 bool replaceText( SourceRange range
, SourceRange replacementRange
);
186 template< typename T
> friend class Plugin::Registration
;
187 enum { isRewriter
= true };
188 bool wouldRewriteWorkdir(SourceLocation loc
);
189 bool reportEditFailure( SourceLocation loc
);
190 bool adjustRangeForOptions( CharSourceRange
* range
, RewriteOptions options
);
194 Plugin registration helper.
196 If you create a new helper class, create also an instance of this class to automatically register it.
197 The passed argument is name of the plugin, used for explicitly invoking rewriter plugins
198 (it is ignored for non-rewriter plugins).
201 static Plugin::Registration< NameOfClass > X( "nameofclass" );
204 template< typename T
>
205 class Plugin::Registration
208 Registration( const char* optionName
, bool byDefault
= !T::isRewriter
);
211 class RegistrationCreate
214 template< typename T
, bool > static T
* create( const InstantiationData
& data
);
218 bool Plugin::ignoreLocation( const Decl
* decl
) const
220 return ignoreLocation( decl
->getLocation());
224 bool Plugin::ignoreLocation( const Stmt
* stmt
) const
226 // Invalid location can happen at least for ImplicitCastExpr of
227 // ImplicitParam 'self' in Objective C method declarations:
228 return stmt
->getBeginLoc().isValid() && ignoreLocation( stmt
->getBeginLoc());
231 inline bool Plugin::ignoreLocation(TypeLoc tloc
) const
233 return ignoreLocation(tloc
.getBeginLoc());
236 template< typename T
>
237 Plugin
* Plugin::createHelper( const InstantiationData
& data
)
239 return new T( data
);
242 template< typename T
>
244 Plugin::Registration
< T
>::Registration( const char* optionName
, bool byDefault
)
246 registerPlugin( &T::template createHelper
< T
>, optionName
, T::isPPCallback
, T::isSharedPlugin
, byDefault
);
250 RewritePlugin::RewriteOptions::RewriteOptions( RewriteOption option
)
253 // Note that 'flags' stores also RemoveLineIfEmpty, it must be kept in sync with the base class.
254 if( flags
& RewritePlugin::RemoveLineIfEmpty
)
255 RemoveLineIfEmpty
= true;
259 RewritePlugin::RewriteOption
operator|( RewritePlugin::RewriteOption option1
, RewritePlugin::RewriteOption option2
)
261 return static_cast< RewritePlugin::RewriteOption
>( int( option1
) | int( option2
));
264 template<typename Derived
>
265 class FilteringRewritePlugin
: public RecursiveASTVisitor
<Derived
>, public RewritePlugin
268 explicit FilteringRewritePlugin( const InstantiationData
& data
) : RewritePlugin(data
) {}
270 bool TraverseNamespaceDecl(NamespaceDecl
* decl
) {
271 if (ignoreLocation(decl
->getBeginLoc()))
273 return RecursiveASTVisitor
<Derived
>::TraverseNamespaceDecl(decl
);
277 void normalizeDotDotInFilePath(std::string
&);
279 // Same as pathname.startswith(prefix), except on Windows, where pathname and
280 // prefix may also contain backslashes:
281 bool hasPathnamePrefix(StringRef pathname
, StringRef prefix
);
283 // Same as pathname == other, except on Windows, where pathname and other may
284 // also contain backslashes:
285 bool isSamePathname(StringRef pathname
, StringRef other
);
287 // Check whether fullPathname is either SRCDIR/include/includePathname or
288 // SDKDIR/include/includePathname:
289 bool isSameUnoIncludePathname(StringRef fullPathname
, StringRef includePathname
);
291 // It appears that, given a function declaration, there is no way to determine
292 // the language linkage of the function's type, only of the function's name
293 // (via FunctionDecl::isExternC); however, in a case like
295 // extern "C" { static void f(); }
297 // the function's name does not have C language linkage while the function's
298 // type does (as clarified in C++11 [decl.link]); cf. <http://clang-developers.
299 // 42468.n3.nabble.com/Language-linkage-of-function-type-tt4037248.html>
300 // "Language linkage of function type":
301 bool hasCLanguageLinkageType(FunctionDecl
const * decl
);
303 // Count the number of times the base class is present in the subclass hierarchy
305 int derivedFromCount(clang::QualType subclassType
, clang::QualType baseclassType
);
306 int derivedFromCount(const CXXRecordDecl
* subtypeRecord
, const CXXRecordDecl
* baseRecord
);
308 // It looks like Clang wrongly implements DR 4
309 // (<http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#4>) and treats
310 // a variable declared in an 'extern "..." {...}'-style linkage-specification as
311 // if it contained the 'extern' specifier:
312 bool hasExternalLinkage(VarDecl
const * decl
);
314 bool isSmartPointerType(const Expr
*);
315 bool isSmartPointerType(clang::QualType
);
317 const Decl
* getFunctionDeclContext(ASTContext
& context
, const Stmt
* stmt
);
321 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */