1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #if !defined _WIN32 //TODO, #include <sys/mman.h>
18 #include <sys/types.h>
26 This is intended to be run as the second stage of the "constfields" clang plugin.
31 class ConstFieldsRewrite
: public RecursiveASTVisitor
<ConstFieldsRewrite
>,
32 public loplugin::RewritePlugin
35 explicit ConstFieldsRewrite(loplugin::InstantiationData
const& data
);
36 ~ConstFieldsRewrite();
38 virtual void run() override
42 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
46 bool VisitFieldDecl(const FieldDecl
* var
);
49 // I use a brute-force approach - mmap the results file and do a linear search on it
50 // It works surprisingly well, because the file is small enough to fit into L2 cache on modern CPU's
56 size_t getFilesize(const char* filename
)
63 ConstFieldsRewrite::ConstFieldsRewrite(loplugin::InstantiationData
const& data
)
66 static const char sInputFile
[] = SRCDIR
"/compilerplugins/clang/constfields.results";
67 mmapFilesize
= getFilesize(sInputFile
);
69 mmapFD
= open(sInputFile
, O_RDONLY
, 0);
72 mmappedData
= static_cast<char*>(mmap(NULL
, mmapFilesize
, PROT_READ
, MAP_PRIVATE
, mmapFD
, 0));
73 assert(mmappedData
!= NULL
);
76 ConstFieldsRewrite::~ConstFieldsRewrite()
79 int rc
= munmap(mmappedData
, mmapFilesize
);
84 bool ConstFieldsRewrite::VisitFieldDecl(const FieldDecl
* fieldDecl
)
86 if (ignoreLocation(fieldDecl
))
88 // ignore stuff that forms part of the stable URE interface
89 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(
90 fieldDecl
->getCanonicalDecl()->getLocation())))
92 // in case we've already processed this field
93 if (fieldDecl
->getType().isConstQualified())
95 // in case we've already processed this field
96 if (fieldDecl
->getType().isConstQualified())
98 // TODO rewriting T& is a bit trickier
99 if (loplugin::TypeCheck(fieldDecl
->getType()).LvalueReference())
102 const RecordDecl
* recordDecl
= fieldDecl
->getParent();
103 std::string parentClassName
;
104 if (const CXXRecordDecl
* cxxRecordDecl
= dyn_cast
<CXXRecordDecl
>(recordDecl
))
106 if (cxxRecordDecl
->getTemplateInstantiationPattern())
107 cxxRecordDecl
= cxxRecordDecl
->getTemplateInstantiationPattern();
108 parentClassName
= cxxRecordDecl
->getQualifiedNameAsString();
112 parentClassName
= recordDecl
->getQualifiedNameAsString();
114 // the extra spaces match the formatting in the results file, and help avoid false+
115 std::string aNiceName
= " " + parentClassName
+ " " + fieldDecl
->getNameAsString() + " "
116 + fieldDecl
->getType().getAsString() + "\n";
118 // search mmap'ed file for field
119 const char* aNiceNameStr
= aNiceName
.c_str();
120 char* found
= std::search(mmappedData
, mmappedData
+ mmapFilesize
, aNiceNameStr
,
121 aNiceNameStr
+ aNiceName
.size());
122 if (!(found
< mmappedData
+ mmapFilesize
))
125 SourceManager
& SM
= compiler
.getSourceManager();
126 auto endLoc
= fieldDecl
->getTypeSourceInfo()->getTypeLoc().getEndLoc();
127 endLoc
= endLoc
.getLocWithOffset(Lexer::MeasureTokenLength(endLoc
, SM
, compiler
.getLangOpts()));
129 // Calculate how much space is available after the type declaration that we can use to
130 // overwrite with the " const". This reduces the amount of formatting fixups I need to do.
131 char const* p1
= SM
.getCharacterData(endLoc
);
132 bool success
= false;
135 // Sometimes there is no space at all e.g. in
136 // FastTokenHandlerBase *mpTokenHandler;
137 // between the "*" and the "mpTokenHandler", so add an extra space.
138 success
= insertText(endLoc
, " const ");
142 int spaceAvailable
= 1;
144 for (; spaceAvailable
< 6; ++spaceAvailable
)
150 if (spaceAvailable
< 6)
151 success
= replaceText(endLoc
, spaceAvailable
- 1, " const");
153 success
= replaceText(endLoc
, spaceAvailable
, " const");
158 report(DiagnosticsEngine::Warning
, "Could not mark field as const",
159 compat::getBeginLoc(fieldDecl
))
160 << fieldDecl
->getSourceRange();
165 loplugin::Plugin::Registration
<ConstFieldsRewrite
> X("constfieldsrewrite", false);
170 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */