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
);
85 bool ConstFieldsRewrite::VisitFieldDecl(const FieldDecl
* fieldDecl
)
87 if (ignoreLocation(fieldDecl
))
89 // ignore stuff that forms part of the stable URE interface
90 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(
91 fieldDecl
->getCanonicalDecl()->getLocation())))
93 // in case we've already processed this field
94 if (fieldDecl
->getType().isConstQualified())
96 // in case we've already processed this field
97 if (fieldDecl
->getType().isConstQualified())
99 // TODO rewriting T& is a bit trickier
100 if (loplugin::TypeCheck(fieldDecl
->getType()).LvalueReference())
103 const RecordDecl
* recordDecl
= fieldDecl
->getParent();
104 std::string parentClassName
;
105 if (const CXXRecordDecl
* cxxRecordDecl
= dyn_cast
<CXXRecordDecl
>(recordDecl
))
107 if (cxxRecordDecl
->getTemplateInstantiationPattern())
108 cxxRecordDecl
= cxxRecordDecl
->getTemplateInstantiationPattern();
109 parentClassName
= cxxRecordDecl
->getQualifiedNameAsString();
113 parentClassName
= recordDecl
->getQualifiedNameAsString();
115 // the extra spaces match the formatting in the results file, and help avoid false+
116 std::string aNiceName
= " " + parentClassName
+ " " + fieldDecl
->getNameAsString() + " "
117 + fieldDecl
->getType().getAsString() + "\n";
119 // search mmap'ed file for field
120 const char* aNiceNameStr
= aNiceName
.c_str();
121 char* found
= std::search(mmappedData
, mmappedData
+ mmapFilesize
, aNiceNameStr
,
122 aNiceNameStr
+ aNiceName
.size());
123 if (!(found
< mmappedData
+ mmapFilesize
))
126 SourceManager
& SM
= compiler
.getSourceManager();
127 auto endLoc
= fieldDecl
->getTypeSourceInfo()->getTypeLoc().getEndLoc();
128 endLoc
= endLoc
.getLocWithOffset(Lexer::MeasureTokenLength(endLoc
, SM
, compiler
.getLangOpts()));
130 // Calculate how much space is available after the type declaration that we can use to
131 // overwrite with the " const". This reduces the amount of formatting fixups I need to do.
132 char const* p1
= SM
.getCharacterData(endLoc
);
133 bool success
= false;
136 // Sometimes there is no space at all e.g. in
137 // FastTokenHandlerBase *mpTokenHandler;
138 // between the "*" and the "mpTokenHandler", so add an extra space.
139 success
= insertText(endLoc
, " const ");
143 int spaceAvailable
= 1;
145 for (; spaceAvailable
< 6; ++spaceAvailable
)
151 if (spaceAvailable
< 6)
152 success
= replaceText(endLoc
, spaceAvailable
- 1, " const");
154 success
= replaceText(endLoc
, spaceAvailable
, " const");
159 report(DiagnosticsEngine::Warning
, "Could not mark field as const",
160 compat::getBeginLoc(fieldDecl
))
161 << fieldDecl
->getSourceRange();
166 loplugin::Plugin::Registration
<ConstFieldsRewrite
> X("constfieldsrewrite", false);
171 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */