Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make std::initializer_list visible. #9

Merged
merged 1 commit into from May 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -281,6 +281,7 @@ add_clang_executable(insights
RangeForStmtHandler.cpp
StaticAssertHandler.cpp
StaticHandler.cpp
StdInitializerListHandler.cpp
StructuredBindingsHandler.cpp
TemplateHandler.cpp
UserDefinedLiteralHandler.cpp
Expand Down
3 changes: 3 additions & 0 deletions CodeGenerator.cpp
Expand Up @@ -899,6 +899,9 @@ void CodeGenerator::InsertArg(const CXXDefaultArgExpr* stmt)

void CodeGenerator::InsertArg(const CXXStdInitializerListExpr* stmt)
{
// No qualifiers like const or volatile here. This appears in function calls or operators as a parameter. CV's are
// not allowed there.
mOutputFormatHelper.Append(GetName(stmt->getType(), Unqualified::Yes));
InsertArg(stmt->getSubExpr());
}
//-----------------------------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions Insights.cpp
Expand Up @@ -42,6 +42,7 @@
#include "RangeForStmtHandler.h"
#include "StaticAssertHandler.h"
#include "StaticHandler.h"
#include "StdInitializerListHandler.h"
#include "StructuredBindingsHandler.h"
#include "TemplateHandler.h"
#include "UserDefinedLiteralHandler.h"
Expand Down Expand Up @@ -86,6 +87,7 @@ class CppInsightASTConsumer final : public ASTConsumer
, mAutoStmtHandler{rewriter, mMatcher}
, mNrvoHandler{rewriter, mMatcher}
, mUserDefinedLiteralHandler{rewriter, mMatcher}
, mStdInitializerListHandler{rewriter, mMatcher}
{
}

Expand All @@ -106,6 +108,7 @@ class CppInsightASTConsumer final : public ASTConsumer
AutoStmtHandler mAutoStmtHandler;
NRVOHandler mNrvoHandler;
UserDefinedLiteralHandler mUserDefinedLiteralHandler;
StdInitializerListHandler mStdInitializerListHandler;
};
//-----------------------------------------------------------------------------

Expand Down
74 changes: 74 additions & 0 deletions StdInitializerListHandler.cpp
@@ -0,0 +1,74 @@
/******************************************************************************
*
* C++ Insights, copyright (C) by Andreas Fertig
* Distributed under an MIT license. See LICENSE for details
*
****************************************************************************/

#include "StdInitializerListHandler.h"
#include "CodeGenerator.h"
#include "InsightsHelpers.h"
#include "InsightsMatchers.h"
#include "InsightsStaticStrings.h"
#include "OutputFormatHelper.h"
//-----------------------------------------------------------------------------

using namespace clang;
using namespace clang::ast_matchers;
//-----------------------------------------------------------------------------

namespace clang::insights {

StdInitializerListHandler::StdInitializerListHandler(Rewriter& rewrite, MatchFinder& matcher)
: InsightsBase(rewrite)
{
const auto operatorMatcher = anyOf(isExpansionInSystemHeader(),
isMacroOrInvalidLocation(),
isTemplate,
hasAncestor(ifStmt()),
hasAncestor(switchStmt()),
/* if we match the top-most CXXOperatorCallExpr we will see all
descendants. So filter them here to avoid getting them multiple times */
hasAncestor(cxxOperatorCallExpr()),
hasLambdaAncestor,
hasAncestor(implicitCastExpr(hasMatchingCast())),
hasAncestor(userDefinedLiteral()),
hasAncestor(cxxForRangeStmt())
#ifdef MATCH_CXX_MEM_CEXPR
,
hasAncestor(cxxMemberCallExpr())
#endif
);

matcher.addMatcher(
cxxStdInitializerListExpr(unless(operatorMatcher), hasParent(expr().bind("expr"))).bind("initializer"), this);
}
//-----------------------------------------------------------------------------

void StdInitializerListHandler::run(const MatchFinder::MatchResult& result)
{
if(const auto* initList = result.Nodes.getNodeAs<CXXStdInitializerListExpr>("initializer")) {
OutputFormatHelper outputFormatHelper{};
CodeGenerator codeGenerator{outputFormatHelper};

const auto* expr = result.Nodes.getNodeAs<CXXConstructExpr>("expr");
const bool isCtorInit{expr && (1 == expr->getNumArgs())}; // If an initializer list appears in a constructor as
// a single argument we need to add braces.

if(isCtorInit) {
outputFormatHelper.Append("{ ");
}

codeGenerator.InsertArg(initList);

if(isCtorInit) {
outputFormatHelper.Append(" }");
}

DPrint("replacementInit: %s\n", outputFormatHelper.GetString());
mRewrite.ReplaceText(initList->getSourceRange(), outputFormatHelper.GetString());
}
}
//-----------------------------------------------------------------------------

} // namespace clang::insights
50 changes: 50 additions & 0 deletions StdInitializerListHandler.h
@@ -0,0 +1,50 @@
/******************************************************************************
*
* C++ Insights, copyright (C) by Andreas Fertig
* Distributed under an MIT license. See LICENSE for details
*
****************************************************************************/

#ifndef INSIGHTS_STD_INITIALIZER_LIST_HANDLER_H
#define INSIGHTS_STD_INITIALIZER_LIST_HANDLER_H

#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Rewrite/Core/Rewriter.h"

#include "InsightsBase.h"
//-----------------------------------------------------------------------------

namespace clang::insights {

/// \brief Show where \c std::initializer_list is used.
///
/// With C++11 uniform initialization and initializer lists we cannot
/// longer easily see whether we are calling a normal constructor or one
/// which takes a initializer_list. For example:
///
/// \begincode
/// struct V {
/// V(int x) {}
/// V(std::initializer_list<int> x) {}
/// };
///
/// V v{1};
/// V vv{1, 2};
/// \endcode
///
/// Surprisingly to some people, in both cases the second constructor, taking
/// a std::initializer_list, is used.
class StdInitializerListHandler final : public ast_matchers::MatchFinder::MatchCallback, public InsightsBase
{
public:
StdInitializerListHandler(Rewriter& rewrite, ast_matchers::MatchFinder& matcher);
void run(const ast_matchers::MatchFinder::MatchResult& result) override;
};
//-----------------------------------------------------------------------------

} // namespace clang::insights

#endif /* INSIGHTS_STD_INITIALIZER_LIST_HANDLER_H */
4 changes: 2 additions & 2 deletions tests/InitalizerListTest.expect
@@ -1,9 +1,9 @@
#include <vector>

int main(){
std::vector<int> myVec{1,2,3,4,5,6,7,8,9};
std::vector<int> myVec{ std::initializer_list<int>{ 1, 2, 3, 4, 5, 6, 7, 8, 9 } };

myVec.operator=({ 1, 2, 3, 4, 5, 6, 7, 8, 9 });
myVec.operator=(std::initializer_list<int>{ 1, 2, 3, 4, 5, 6, 7, 8, 9 });

}

63 changes: 63 additions & 0 deletions tests/InitializerListTest.cpp
@@ -0,0 +1,63 @@
#include <utility>

class X {
public:
~X() {}

X(std::initializer_list<int> x) {}

X(int z, std::initializer_list<int> x) {}

X(std::initializer_list<int> x, int z) {}

X(void *x, int y) {}

X& operator+=(const std::initializer_list<int>& x)
{
return *this;
}
};

struct V {
V(int x) {}
V(std::initializer_list<int> x) {}

};

struct Y { int x, y; };

void takes_y(Y y);

void bar(std::initializer_list<int> x) {}


template<typename T>
void something(std::initializer_list<T>) {}

void foo() {
X{1, 2, 3};
X{nullptr, 0};

X x{3, 4, 5};
X b{1};

X{1, {2, 3}};
X c{1, {2, 3}};

X{{1, 2}, 3};
X d{{1, 2}, 3};

b += {2 ,4};

takes_y({1, 2});

bar( {1, 2} );

something( {1 , 2} );

something( {1.0f , 2.0f} );

V v{1};
V vv{1, 2};
}

85 changes: 85 additions & 0 deletions tests/InitializerListTest.expect
@@ -0,0 +1,85 @@
#include <utility>

class X {
public:
~X() {}

X(std::initializer_list<int> x) {}

X(int z, std::initializer_list<int> x) {}

X(std::initializer_list<int> x, int z) {}

X(void *x, int y) {}

X& operator+=(const std::initializer_list<int>& x)
{
return *this;
}
/* public: inline constexpr X(const X &); */
};

struct V {
V(int x) {}
V(std::initializer_list<int> x) {}

/* public: inline constexpr V(const V &); */
/* public: inline constexpr V(V &&); */
};

struct Y { int x, y; /* public: inline ~Y() noexcept; */
};

void takes_y(Y y);

void bar(std::initializer_list<int> x) {}


template<typename T>
void something(std::initializer_list<T>) {}

/* First instantiated from: InitializerListTest.cpp:56 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void something<int>(std::initializer_list<int>)
{
}
#endif


/* First instantiated from: InitializerListTest.cpp:58 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void something<float>(std::initializer_list<float>)
{
}
#endif


void foo() {
X{ std::initializer_list<int>{ 1, 2, 3 } };
X{nullptr, 0};

X x{ std::initializer_list<int>{ 3, 4, 5 } };
X b{ std::initializer_list<int>{ 1 } };

X{1, std::initializer_list<int>{ 2, 3 }};
X c{1, std::initializer_list<int>{ 2, 3 }};

X{std::initializer_list<int>{ 1, 2 }, 3};
X d{std::initializer_list<int>{ 1, 2 }, 3};

b.operator+=(std::initializer_list<int>{ 2, 4 });

takes_y({1, 2});

bar( std::initializer_list<int>{ 1, 2 } );

something( std::initializer_list<int>{ 1, 2 } );

something( std::initializer_list<float>{ 1.0f, 2.0f } );

V v{ std::initializer_list<int>{ 1 } };
V vv{ std::initializer_list<int>{ 1, 2 } };
}

2 changes: 1 addition & 1 deletion tests/LambdaHandler7Test.expect
Expand Up @@ -3,7 +3,7 @@

int main()
{
std::vector<int> myVec{1,2,3,4,5};
std::vector<int> myVec{ std::initializer_list<int>{ 1, 2, 3, 4, 5 } };


class __lambda_8_57
Expand Down
2 changes: 1 addition & 1 deletion tests/RangeForStmtHandler2Test.expect
Expand Up @@ -19,7 +19,7 @@ int main()
}
}

std::vector<int> v{1, 2, 3, 5};
std::vector<int> v{ std::initializer_list<int>{ 1, 2, 3, 5 } };

{
std::vector<int, std::allocator<int> > & __range1 = v;
Expand Down
2 changes: 1 addition & 1 deletion tests/RangeForStmtHandlerTest.expect
Expand Up @@ -108,7 +108,7 @@ int main()
}
}

std::vector<int> v{1, 2, 3, 5};
std::vector<int> v{ std::initializer_list<int>{ 1, 2, 3, 5 } };

{
std::vector<int, std::allocator<int> > & __range1 = v;
Expand Down
2 changes: 1 addition & 1 deletion tests/TemplateExpansionTest.expect
Expand Up @@ -55,7 +55,7 @@ void foo2() {
template<int fp(void)> class testDecl { };
/* First instantiated from: TemplateExpansionTest.cpp:45 */
#ifdef INSIGHTS_USE_TEMPLATE
class testDecl</* INSIGHTS-TODO: CodeGenerator.cpp:927 stmt: Function */>
class testDecl</* INSIGHTS-TODO: CodeGenerator.cpp:931 stmt: Function */>
{

};
Expand Down