Skip to content

Adds duplicate feature #375

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions clang/include/clang/3C/Duplicate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef LLVM_DUPLICATE_H
#define LLVM_DUPLICATE_H

#include "ProgramInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include <getopt.h>

typedef std::function<bool (clang::VarDecl*)> selector;

// Create a duplicate of a variable.
// ToScan is the context to search for the variable
// P is a predicate that decides which variable to make a duplicate of
// Returns the name of the newly created variable
// or None if no variable matching P is found
Option<std::string> createDuplicate(clang::ASTContext &Context,
clang::Rewriter &R, ProgramInfo &Info,
clang::Decl *ToScan, selector P);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering: Why this interface for determining the variable to duplicate? That is, I could imagine just specifying a single Decl and duplicating that. Or I could imagine providing a variable name, and you'd search for the proper decl. Just curious.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This just seemed like the most general interface in case this becomes useful for other modules down the line. One change could be adding some top level helpers for simpler functionality.




#endif //LLVM_DUPLICATE_H
1 change: 1 addition & 0 deletions clang/lib/3C/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ set( LLVM_LINK_COMPONENTS
StructInit.cpp
TypeVariableAnalysis.cpp
Utils.cpp
Duplicate.cpp
${five_c_source}
LINK_LIBS
clangAST
Expand Down
80 changes: 80 additions & 0 deletions clang/lib/3C/Duplicate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include "clang/3C/Duplicate.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/3C/ProgramInfo.h"
#include "clang/Rewrite/Core/Rewriter.h"

using namespace clang;
using namespace llvm;
using namespace std;


// Recursive Visitor
class FindVarDecl : public RecursiveASTVisitor<FindVarDecl> {
public:
explicit FindVarDecl(ASTContext &Context, Rewriter &R,
ProgramInfo &I, selector P)
: Context(Context), R(R), Info(I), P(P) {}


bool VisitVarDecl(VarDecl *VD) {
// If the selector matches execute the duplicate function
// and store the new name in the optional
if(P(VD)){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if this is true twice? I imagine you expect it won't be, but is there a reason it couldn't?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return false at the bottom should prevent this. It will stop traversing once it hits a positive

auto NewName = addDuplicate(VD);
Replacement = { NewName };
return false;
} else {
return true;
}
}

Option<string> didReplace(void) {
return Replacement;
}

private:
// Insert the duplicate into the rewriter
// Returns the new var's name
string addDuplicate(VarDecl *VD) {
SourceLocation End = VD->getEndLoc();
auto Dup = createDuplicateString(VD);
R.InsertTextAfterToken(End, Dup.second);
return Dup.first;
}

// Create the text for the new variable
// Returns a pair containing the new name
// and the new line containing declaration and assignment
pair<string,string> createDuplicateString(VarDecl *VD) {
auto CV = Info.getVariable(VD, &Context);
auto Type =
CV.hasValue() ?
CV.getValue()
.mkString(Info.getConstraints().getVariables(),
false)
: VD->getType().getAsString();
auto TargetName = VD->getNameAsString();
auto NewName = "__" + TargetName + "_copy";
return make_pair(NewName, ";\n" + Type + " " + NewName + "= " + TargetName + "");
}



ASTContext &Context;
Rewriter &R;
ProgramInfo &Info;
// Predicate for finding the variable to duplicate
selector P;
// Duplicate's name or none if var not found
Option<string> Replacement = {};
};

// Main entrypoint
Option<string> createDuplicate(ASTContext &Context, Rewriter &R,
ProgramInfo &Info,
Decl *FD, selector P) {
auto V = FindVarDecl(Context, R, Info, P);
V.TraverseDecl(FD);
return V.didReplace();
}