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>
17 #include "config_clang.h"
19 #include <sys/types.h>
27 This is intended to be run as the second stage of the "constfields" clang plugin.
32 class ConstFieldsRewrite
: public RecursiveASTVisitor
<ConstFieldsRewrite
>,
33 public loplugin::RewritePlugin
36 explicit ConstFieldsRewrite(loplugin::InstantiationData
const& data
);
37 ~ConstFieldsRewrite();
39 virtual void run() override
43 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
47 bool VisitFieldDecl(const FieldDecl
* var
);
50 // I use a brute-force approach - mmap the results file and do a linear search on it
51 // It works surprisingly well, because the file is small enough to fit into L2 cache on modern CPU's
57 size_t getFilesize(const char* filename
)
64 ConstFieldsRewrite::ConstFieldsRewrite(loplugin::InstantiationData
const& data
)
67 static const char sInputFile
[] = SRCDIR
"/compilerplugins/clang/constfields.results";
68 mmapFilesize
= getFilesize(sInputFile
);
70 mmapFD
= open(sInputFile
, O_RDONLY
, 0);
73 mmappedData
= static_cast<char*>(mmap(NULL
, mmapFilesize
, PROT_READ
, MAP_PRIVATE
, mmapFD
, 0));
74 assert(mmappedData
!= NULL
);
77 ConstFieldsRewrite::~ConstFieldsRewrite()
80 int rc
= munmap(mmappedData
, mmapFilesize
);
86 bool ConstFieldsRewrite::VisitFieldDecl(const FieldDecl
* fieldDecl
)
88 if (ignoreLocation(fieldDecl
))
90 // ignore stuff that forms part of the stable URE interface
91 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(
92 fieldDecl
->getCanonicalDecl()->getLocation())))
94 // in case we've already processed this field
95 if (fieldDecl
->getType().isConstQualified())
97 // TODO rewriting T& is a bit trickier
98 if (loplugin::TypeCheck(fieldDecl
->getType()).LvalueReference())
101 const RecordDecl
* recordDecl
= fieldDecl
->getParent();
102 std::string parentClassName
;
103 if (const CXXRecordDecl
* cxxRecordDecl
= dyn_cast
<CXXRecordDecl
>(recordDecl
))
105 if (cxxRecordDecl
->getTemplateInstantiationPattern())
106 cxxRecordDecl
= cxxRecordDecl
->getTemplateInstantiationPattern();
107 parentClassName
= cxxRecordDecl
->getQualifiedNameAsString();
111 parentClassName
= recordDecl
->getQualifiedNameAsString();
113 // the extra spaces match the formatting in the results file, and help avoid false+
114 std::string aNiceName
= " " + parentClassName
+ " " + fieldDecl
->getNameAsString() + " "
115 + fieldDecl
->getType().getAsString() + "\n";
117 // search mmap'ed file for field
118 const char* aNiceNameStr
= aNiceName
.c_str();
119 char* found
= std::search(mmappedData
, mmappedData
+ mmapFilesize
, aNiceNameStr
,
120 aNiceNameStr
+ aNiceName
.size());
121 if (!(found
< mmappedData
+ mmapFilesize
))
124 SourceManager
& SM
= compiler
.getSourceManager();
125 auto endLoc
= fieldDecl
->getTypeSourceInfo()->getTypeLoc().getEndLoc();
126 endLoc
= endLoc
.getLocWithOffset(Lexer::MeasureTokenLength(endLoc
, SM
, compiler
.getLangOpts()));
128 // Calculate how much space is available after the type declaration that we can use to
129 // overwrite with the " const". This reduces the amount of formatting fixups I need to do.
130 char const* p1
= SM
.getCharacterData(endLoc
);
131 bool success
= false;
134 // Sometimes there is no space at all e.g. in
135 // FastTokenHandlerBase *mpTokenHandler;
136 // between the "*" and the "mpTokenHandler", so add an extra space.
137 success
= insertText(endLoc
, " const ");
141 int spaceAvailable
= 1;
143 for (; spaceAvailable
< 6; ++spaceAvailable
)
149 if (spaceAvailable
< 6)
150 success
= replaceText(endLoc
, spaceAvailable
- 1, " const");
152 success
= replaceText(endLoc
, spaceAvailable
, " const");
157 report(DiagnosticsEngine::Warning
, "Could not mark field as const",
158 fieldDecl
->getBeginLoc())
159 << fieldDecl
->getSourceRange();
164 loplugin::Plugin::Registration
<ConstFieldsRewrite
> X("constfieldsrewrite", false);
169 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */