diff --git a/src/propagation/block_visitor_manager.h b/src/propagation/block_visitor_manager.h index 3026988..449ed4e 100644 --- a/src/propagation/block_visitor_manager.h +++ b/src/propagation/block_visitor_manager.h @@ -215,7 +215,7 @@ template class BlockVisitorManager { */ bool lookup(ResultType &result, const std::string &variable, const clang::SourceLocation &location) const { - return valueMap.lookup(result, variable, location); + return valueMap.lookup(result, variable, location, context.getSourceManager()); } /** diff --git a/src/propagation/types/value_context_map.h b/src/propagation/types/value_context_map.h index 121a49c..f323655 100644 --- a/src/propagation/types/value_context_map.h +++ b/src/propagation/types/value_context_map.h @@ -8,6 +8,8 @@ #include #include +#include + namespace clangmetatool { namespace propagation { namespace types { @@ -91,13 +93,14 @@ template class ValueContextMap { * Return false if no context is found. */ bool lookup(ResultType &result, const std::string &variable, - const clang::SourceLocation &location) const { + const clang::SourceLocation &location, + clang::SourceManager &SM) const { auto it = map.find(variable); if (map.end() != it) { // Find the last definition before the location for (auto sit = it->second.rbegin(); sit != it->second.rend(); ++sit) { - if (std::get<0>(*sit) < location) { + if (SM.isBeforeInTranslationUnit(std::get<0>(*sit), location)) { result = std::get<2>(*sit); return true; diff --git a/t/026-macro-propagation.t.cpp b/t/026-macro-propagation.t.cpp new file mode 100644 index 0000000..6dd2444 --- /dev/null +++ b/t/026-macro-propagation.t.cpp @@ -0,0 +1,184 @@ +#include "clangmetatool-testconfig.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include + +#include + +namespace { + +using namespace clang::ast_matchers; + +using FindCalls = clangmetatool::collectors::FindCalls; + +using FindVarDeclsDatum = std::pair; +using FindVarDeclsData = std::vector; + +class FindVarDeclsCallback : public MatchFinder::MatchCallback { +private: + clang::CompilerInstance* ci; + FindVarDeclsData* data; + +public: + FindVarDeclsCallback(clang::CompilerInstance* ci, FindVarDeclsData* data) + : ci(ci), data(data) { + } + + virtual void run(const MatchFinder::MatchResult& r) override { + const clang::FunctionDecl* f = r.Nodes.getNodeAs("func"); + + const clang::DeclRefExpr* d = r.Nodes.getNodeAs("declRef"); + + data->push_back({f, d}); + } +}; + +class FindVarDecls { +private: + FindVarDeclsData data; + + StatementMatcher matcher = + (declRefExpr + (hasDeclaration + (varDecl + (hasAnyName + ( + "v1" + ) + ) + ), + hasAncestor( + functionDecl().bind("func") + ) + ) + ).bind("declRef"); + + FindVarDeclsCallback callback; + +public: + FindVarDecls(clang::CompilerInstance* ci, + MatchFinder* f) + : callback(ci, &data) + { + f->addMatcher(matcher, &callback); + } + + FindVarDeclsData* getData() { return &data; } +}; + +class MyTool { +private: + clang::CompilerInstance* ci; + FindVarDecls fvd; + clangmetatool::propagation::ConstantCStringPropagator csp; + + std::unique_ptr callObject; + + + +public: + MyTool(clang::CompilerInstance* ci, MatchFinder *f) + : ci(ci), fvd(ci, f), csp(ci) { + callObject = std::unique_ptr(new FindCalls(ci, f, "foo")); // initialize function finder + } + + + + void postProcessing + (std::map &replacementsMap) { + FindVarDeclsData* decls = fvd.getData(); + + + + EXPECT_EQ(decls->size(), 2); + + auto macroStr = decls->at(0).second->getLocStart().printToString(ci->getSourceManager()); + EXPECT_EQ("5:3", macroStr.substr(macroStr.find(":", 0) + 1, 3)); + // FUNC(v1) + + auto funcStr = decls->at(1).second->getLocStart().printToString(ci->getSourceManager()); + EXPECT_EQ("6:7", funcStr.substr(macroStr.find(":", 0) + 1, 3)); + // foo(v1); + + EXPECT_FALSE(decls->at(0).second->getLocStart() < decls->at(1).second->getLocStart()); + // Using "<" for comparing source location is not correct + + EXPECT_TRUE( + ci->getASTContext().getSourceManager().isBeforeInTranslationUnit( + decls->at(0).second->getLocStart(), + decls->at(1).second->getLocStart())); + + + auto call_context = callObject->getData()->call_context; + const clang::FunctionDecl *decl; + const clang::CallExpr *call; + + EXPECT_EQ(2, call_context.size()); + const auto &p = call_context.begin(); // Check only the first function call + + std::tie(decl, call) = (*p); + const auto result = csp.runPropagation(decl, reinterpret_cast (call->getArg(0)->IgnoreImplicit())); + + std::ostringstream temp; + result.print(temp); + EXPECT_STREQ("something", temp.str().c_str()); + + + + } +}; + +} // namespace anonymous + +TEST(propagation_MacroConstantPropagation, basic) { + llvm::cl::OptionCategory MyToolCategory("my-tool options"); + int argc = 4; + const char* argv[] = { + "foo", + CMAKE_SOURCE_DIR "/t/data/026-macro-propagation/foo.cpp", + "--", + "-xc" + }; + clang::tooling::CommonOptionsParser optionsParser + (argc, argv, MyToolCategory); + clang::tooling::RefactoringTool tool + (optionsParser.getCompilations(), optionsParser.getSourcePathList()); + clangmetatool::MetaToolFactory> + 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 ---------------------------------- diff --git a/t/CMakeLists.txt b/t/CMakeLists.txt index 1e5bc0b..33f61b9 100644 --- a/t/CMakeLists.txt +++ b/t/CMakeLists.txt @@ -33,6 +33,7 @@ foreach( 023-multi-function-integer-propagation 024-find-cxx-member-calls 025-find-mixed-calls + 026-macro-propagation ) add_executable(${TEST}.t ${TEST}.t.cpp) diff --git a/t/data/026-macro-propagation/a.h b/t/data/026-macro-propagation/a.h new file mode 100644 index 0000000..c490588 --- /dev/null +++ b/t/data/026-macro-propagation/a.h @@ -0,0 +1,21 @@ +void foo(const char* v1); + +#define FUNC(v1) \ + foo(v1); + + +// ---------------------------------------------------------------------------- +// 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 ---------------------------------- diff --git a/t/data/026-macro-propagation/foo.cpp b/t/data/026-macro-propagation/foo.cpp new file mode 100644 index 0000000..9da3797 --- /dev/null +++ b/t/data/026-macro-propagation/foo.cpp @@ -0,0 +1,24 @@ +#include "a.h" + +int main(){ + char* v1 = "something"; + FUNC(v1); + foo(v1); +} + + +// ---------------------------------------------------------------------------- +// 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 ----------------------------------