Skip to content

Commit

Permalink
Add collector for CXX method calls
Browse files Browse the repository at this point in the history
Signed-off-by: Anthony Burzillo <aburzillo@bloomberg.net>
  • Loading branch information
burz authored and ruoso committed Sep 11, 2018
1 parent cc4de47 commit 6541b32
Show file tree
Hide file tree
Showing 7 changed files with 414 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ add_library(

src/collectors/definitions.cpp
src/collectors/find_calls.cpp
src/collectors/find_cxx_member_calls.cpp
src/collectors/include_graph/find_decl_match_callback.cpp
src/collectors/include_graph/find_decl_ref_match_callback.cpp
src/collectors/include_graph/find_type_match_callback.cpp
Expand Down
73 changes: 73 additions & 0 deletions include/clangmetatool/collectors/find_cxx_member_calls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#ifndef INCLUDED_CLANGMETATOOL_COLLECTORS_FIND_CXX_MEMBER_CALLS_H
#define INCLUDED_CLANGMETATOOL_COLLECTORS_FIND_CXX_MEMBER_CALLS_H

#include <clang/Frontend/CompilerInstance.h>
#include <clang/ASTMatchers/ASTMatchFinder.h>

#include <clangmetatool/collectors/find_cxx_member_calls_data.h>

namespace clangmetatool {
namespace collectors {

/**
* forward declaration to implementation details of the
* collector.
*/
class FindCXXMemberCallsImpl;

/**
* Find Calls data collector. Collects the caller and references
* to the specified function and one of its arguments.
*/
class FindCXXMemberCalls {
private:

/**
* Pointer to Implementation
*/
FindCXXMemberCallsImpl* impl;

public:

/**
* Explicit constructor, to allow for implementation details:
* - ci is a pointer to an instance of the clang compiler
* - f is a pointer to an instance of the MatchFinder class
* - c is a string value of the fully-qualified class/struct name to match on
* - n is a string value of the method name to match on
*/
FindCXXMemberCalls( clang::CompilerInstance *ci,
clang::ast_matchers::MatchFinder *f,
const std::string& c,
const std::string& n );

/**
* Explicit destructor.
*/
~FindCXXMemberCalls();

/**
* Get the pointer to the data structure, populated or not.
*/
FindCXXMemberCallsData* getData();

};
}
}

#endif
// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
40 changes: 40 additions & 0 deletions include/clangmetatool/collectors/find_cxx_member_calls_data.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef INCLUDED_CLANGMETATOOL_COLLECTORS_FIND_CXX_MEMBER_CALLS_DATA_H
#define INCLUDED_CLANGMETATOOL_COLLECTORS_FIND_CXX_MEMBER_CALLS_DATA_H

#include <map>

#include <clang/AST/Decl.h>
#include <clang/AST/ExprCXX.h>

namespace clangmetatool {
namespace collectors {

/**
* The data collected by the FindCXXMemberCalls collector
*
* The declaration of the function and the context in which it occurs
*/
using FindCXXMemberCallsData =
std::multimap<const clang::FunctionDecl*,
const clang::CXXMemberCallExpr*>;

}
}

#endif

// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
136 changes: 136 additions & 0 deletions src/collectors/find_cxx_member_calls.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#include <clangmetatool/collectors/find_cxx_member_calls.h>

#include <string>
#include <memory>

#include <clangmetatool/collectors/find_cxx_member_calls_data.h>

namespace clangmetatool {
namespace collectors {

using namespace clang::ast_matchers;

class AnnotateCall1
: public clang::ast_matchers::MatchFinder::MatchCallback {
private:
clang::CompilerInstance *ci;
FindCXXMemberCallsData *data;
public:
AnnotateCall1
(clang::CompilerInstance* ci,
FindCXXMemberCallsData *data)
:ci(ci), data(data) {}

virtual void
run(const clang::ast_matchers::MatchFinder::MatchResult &r)
override {

const auto c =
r.Nodes.getNodeAs<clang::CXXMemberCallExpr>("call");

const auto f =
r.Nodes.getNodeAs<clang::FunctionDecl>("context");

data->insert
(std::pair
<const clang::FunctionDecl*,
const clang::CXXMemberCallExpr*>(f,c));
}

};

class FindCXXMemberCallsImpl {
private:
std::string c;
std::string n;
FindCXXMemberCallsData data;
clang::CompilerInstance *ci;

std::unique_ptr<StatementMatcher> sm;
AnnotateCall1 cb1;

public:
FindCXXMemberCallsImpl
(clang::CompilerInstance* ci, clang::ast_matchers::MatchFinder* f,
const std::string& c, const std::string& n)
: ci(ci), c(c), n(n), cb1(ci, &data)
{
const auto cType =
type(
hasUnqualifiedDesugaredType(
recordType(
hasDeclaration(
cxxRecordDecl(
hasName(c)
)
)
)
)
);

const auto cExpr =
expr(
anyOf(
hasType(cType),
hasType(
qualType(
pointsTo(cType)
)
)
)
);

sm = std::make_unique<StatementMatcher>(
cxxMemberCallExpr(
on(cExpr),
callee(
cxxMethodDecl(
hasName(n)
)
),
hasAncestor(functionDecl().bind("context"))
).bind("call"));

f->addMatcher(*sm, &cb1);
}

~FindCXXMemberCallsImpl() {
}

FindCXXMemberCallsData* getData() {
return &data;
}

};

FindCXXMemberCalls::FindCXXMemberCalls
(clang::CompilerInstance* ci, clang::ast_matchers::MatchFinder* f,
const std::string& c, const std::string& n)
{
impl = new FindCXXMemberCallsImpl(ci, f, c, n);
}

FindCXXMemberCalls::~FindCXXMemberCalls() {
delete impl;
}

FindCXXMemberCallsData* FindCXXMemberCalls::getData() {
return impl->getData();
}
}
}
// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
124 changes: 124 additions & 0 deletions t/024-find-cxx-member-calls.t.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#include "clangmetatool-testconfig.h"

#include <gtest/gtest.h>

#include <clangmetatool/meta_tool_factory.h>
#include <clangmetatool/meta_tool.h>
#include <clangmetatool/collectors/find_cxx_member_calls.h>

#include <clang/Frontend/FrontendAction.h>
#include <clang/Tooling/Core/Replacement.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>
#include <clang/Tooling/Refactoring.h>
#include <llvm/Support/CommandLine.h>

class MyTool {
private:
clang::CompilerInstance* ci;

std::string cNS = std::string("NakedStruct");
std::string nNSfoo = std::string("foo");
clangmetatool::collectors::FindCXXMemberCalls fcNSfoo;
std::string nNSbar = std::string("bar");
clangmetatool::collectors::FindCXXMemberCalls fcNSbar;

std::string cNC = std::string("NakedClass");
std::string nNCfoo = std::string("foo");
clangmetatool::collectors::FindCXXMemberCalls fcNCfoo;
std::string nNCbar = std::string("bar");
clangmetatool::collectors::FindCXXMemberCalls fcNCbar;

std::string cBS = std::string("suit::BusinessStruct");
std::string nBSfoo = std::string("foo");
clangmetatool::collectors::FindCXXMemberCalls fcBSfoo;
std::string nBSbar = std::string("bar");
clangmetatool::collectors::FindCXXMemberCalls fcBSbar;

std::string cBC = std::string("suit::BusinessClass");
std::string nBCbook = std::string("book");
clangmetatool::collectors::FindCXXMemberCalls fcBCbook;
std::string nBCdiatribe = std::string("diatribe");
clangmetatool::collectors::FindCXXMemberCalls fcBCdiatribe;
public:

MyTool(clang::CompilerInstance* ci, clang::ast_matchers::MatchFinder *f)
: ci(ci)
, fcNSfoo(ci, f, cNS, nNSfoo)
, fcNSbar(ci, f, cNS, nNSbar)
, fcNCfoo(ci, f, cNC, nNCfoo)
, fcNCbar(ci, f, cNC, nNCbar)
, fcBSfoo(ci, f, cBS, nBSfoo)
, fcBSbar(ci, f, cBS, nBSbar)
, fcBCbook(ci, f, cBC, nBCbook)
, fcBCdiatribe(ci, f, cBC, nBCdiatribe)
{}

static void validateFind(clangmetatool::collectors::FindCXXMemberCalls& fc,
const std::string& c, const std::string n) {
const auto data = fc.getData();

ASSERT_EQ(1, data->size());

auto found = data->begin();

EXPECT_EQ("foo", found->first->getNameInfo().getAsString());
EXPECT_EQ(c, found->second->getRecordDecl()->getQualifiedNameAsString());
EXPECT_EQ(n, found->second->getMethodDecl()->getNameAsString());
}

void postProcessing
(std::map<std::string, clang::tooling::Replacements> &replacementsMap) {
validateFind(fcNSfoo, cNS, nNSfoo);
validateFind(fcNSbar, cNS, nNSbar);
validateFind(fcNCfoo, cNC, nNCfoo);
validateFind(fcNCbar, cNC, nNCbar);
validateFind(fcBSfoo, cBS, nBSfoo);
validateFind(fcBSbar, cBS, nBSbar);
validateFind(fcBCbook, cBC, nBCbook);
validateFind(fcBCdiatribe, cBC, nBCdiatribe);
}
};

TEST(use_meta_tool, factory) {
llvm::cl::OptionCategory MyToolCategory("my-tool options");

int argc = 4;
const char* argv[] = {
"foo",
CMAKE_SOURCE_DIR "/t/data/024-find-cxx-member-calls/foo.cpp",
"--",
"-xc++"
};

clang::tooling::CommonOptionsParser
optionsParser
( argc, argv,
MyToolCategory );
clang::tooling::RefactoringTool tool
( optionsParser.getCompilations(),
optionsParser.getSourcePathList());

clangmetatool::MetaToolFactory< clangmetatool::MetaTool<MyTool> >
raf(tool.getReplacements());

int r = tool.runAndSave(&raf);
ASSERT_EQ(0, r);
}


// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
1 change: 1 addition & 0 deletions t/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ foreach(
021-branching-integer-propagation
022-looping-integer-propagation
023-multi-function-integer-propagation
024-find-cxx-member-calls
)

add_executable(${TEST}.t ${TEST}.t.cpp)
Expand Down
Loading

0 comments on commit 6541b32

Please sign in to comment.